mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
GPU: Move post shader handling to new class.
Currently, Vulkan is not working properly and direct (RAM -> output) is not hooked up. But in general, it works.
This commit is contained in:
parent
d17c5b30e1
commit
cb94487a16
13 changed files with 372 additions and 611 deletions
|
@ -68,13 +68,12 @@ FramebufferManagerCommon::~FramebufferManagerCommon() {
|
|||
}
|
||||
bvfbs_.clear();
|
||||
|
||||
SetNumExtraFBOs(0);
|
||||
|
||||
delete presentation_;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::Init() {
|
||||
BeginFrame();
|
||||
presentation_->UpdatePostShader();
|
||||
}
|
||||
|
||||
bool FramebufferManagerCommon::UpdateSize() {
|
||||
|
@ -88,7 +87,7 @@ bool FramebufferManagerCommon::UpdateSize() {
|
|||
bloomHack_ = g_Config.iBloomHack;
|
||||
useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
|
||||
presentation_->UpdateSize(pixelWidth_, pixelHeight_);
|
||||
presentation_->UpdateSize(pixelWidth_, pixelHeight_, renderWidth_, renderHeight_);
|
||||
|
||||
return newRender || newSettings;
|
||||
}
|
||||
|
@ -128,19 +127,6 @@ bool FramebufferManagerCommon::ShouldDownloadFramebuffer(const VirtualFramebuffe
|
|||
return PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x04154000;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::SetNumExtraFBOs(int num) {
|
||||
for (size_t i = 0; i < extraFBOs_.size(); i++) {
|
||||
extraFBOs_[i]->ReleaseAssertLast();
|
||||
}
|
||||
extraFBOs_.clear();
|
||||
for (int i = 0; i < num; i++) {
|
||||
// No depth/stencil for post processing
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ (int)renderWidth_, (int)renderHeight_, 1, 1, false, Draw::FBO_8888 });
|
||||
extraFBOs_.push_back(fbo);
|
||||
}
|
||||
currentRenderVfb_ = 0;
|
||||
}
|
||||
|
||||
// Heuristics to figure out the size of FBO to create.
|
||||
// TODO: Possibly differentiate on whether through mode is used (since in through mode, viewport is meaningless?)
|
||||
void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height) {
|
||||
|
@ -719,48 +705,40 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
|||
float v0 = 0.0f, v1 = 1.0f;
|
||||
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272, u1, v1);
|
||||
|
||||
struct CardboardSettings cardboardSettings;
|
||||
presentation_->GetCardboardSettings(&cardboardSettings);
|
||||
|
||||
// This might draw directly at the backbuffer (if so, applyPostShader is set) so if there's a post shader, we need to apply it here.
|
||||
// Should try to unify this path with the regular path somehow, but this simple solution works for most of the post shaders
|
||||
// (it always runs at output resolution so FXAA may look odd).
|
||||
float x, y, w, h;
|
||||
int uvRotation = useBufferedRendering_ ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation);
|
||||
if (applyPostShader && useBufferedRendering_) {
|
||||
// Might've changed if the shader was just changed to Off.
|
||||
if (usePostShader_) {
|
||||
PostShaderUniforms uniforms{};
|
||||
presentation_->CalculatePostShaderUniforms(512, 272, renderWidth_, renderHeight_, textureCache_->VideoIsPlaying(), &uniforms);
|
||||
BindPostShader(uniforms);
|
||||
} else {
|
||||
Bind2DShader();
|
||||
}
|
||||
} else {
|
||||
// TODO: Currently we can't access the texture from Draw.
|
||||
//if (!applyPostShader) {
|
||||
// TODO: Does this need to bind the backbuffer? What is this doing?
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation);
|
||||
|
||||
Bind2DShader();
|
||||
}
|
||||
|
||||
// We are drawing directly to the back buffer.
|
||||
if (needBackBufferYSwap_)
|
||||
std::swap(v0, v1);
|
||||
|
||||
DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags = flags | DRAWTEX_TO_BACKBUFFER;
|
||||
if (cardboardSettings.enabled) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX);
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags = flags | DRAWTEX_TO_BACKBUFFER;
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
/*} else {
|
||||
OutputFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? OutputFlags::LINEAR : OutputFlags::NEAREST;
|
||||
if (needBackBufferYSwap_) {
|
||||
flags |= OutputFlags::BACKBUFFER_FLIPPED;
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
PostShaderUniforms uniforms{};
|
||||
presentation_->CalculatePostShaderUniforms(512, 272, textureCache_->VideoIsPlaying(), &uniforms);
|
||||
|
||||
// TODO: DrawActiveTexture reverses these, but I'm not sure why? Investigate.
|
||||
if (GetGPUBackend() == GPUBackend::DIRECT3D9 || GetGPUBackend() == GPUBackend::DIRECT3D11) {
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
// TODO
|
||||
presentation_->SourceTexture();
|
||||
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1, uniforms);
|
||||
}*/
|
||||
|
||||
// PresentationCommon sets all kinds of state, we can't rely on anything.
|
||||
gstate_c.Dirty(DIRTY_ALL);
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb) {
|
||||
|
@ -793,7 +771,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black");
|
||||
// No framebuffer to display! Clear to black.
|
||||
if (useBufferedRendering_) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
|
@ -856,7 +833,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
if (Memory::IsValidAddress(fbaddr)) {
|
||||
// The game is displaying something directly from RAM. In GTA, it's decoded video.
|
||||
if (!vfb) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
if (useBufferedRendering_) {
|
||||
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
|
@ -872,7 +848,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
DEBUG_LOG(FRAMEBUF, "Found no FBO to display! displayFBPtr = %08x", fbaddr);
|
||||
// No framebuffer to display! Clear to black.
|
||||
if (useBufferedRendering_) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
}
|
||||
|
@ -913,88 +888,33 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
float u1 = (480.0f + offsetX) / (float)vfb->bufferWidth;
|
||||
float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight;
|
||||
|
||||
textureCache_->ForgetLastTexture();
|
||||
|
||||
OutputFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? OutputFlags::LINEAR : OutputFlags::NEAREST;
|
||||
if (needBackBufferYSwap_) {
|
||||
flags |= OutputFlags::BACKBUFFER_FLIPPED;
|
||||
}
|
||||
|
||||
if (!usePostShader_) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
PostShaderUniforms uniforms{};
|
||||
int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
|
||||
int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
|
||||
presentation_->CalculatePostShaderUniforms(actualWidth, actualHeight, textureCache_->VideoIsPlaying(), &uniforms);
|
||||
|
||||
// TODO: DrawActiveTexture reverses these, but I'm not sure why? Investigate.
|
||||
if (GetGPUBackend() == GPUBackend::DIRECT3D9 || GetGPUBackend() == GPUBackend::DIRECT3D11) {
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
presentation_->SourceFramebuffer(vfb->fbo);
|
||||
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1);
|
||||
} else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) {
|
||||
// An additional pass, post-processing shader to the extra FBO.
|
||||
shaderManager_->DirtyLastShader(); // dirty lastShader_
|
||||
draw_->BindFramebufferAsRenderTarget(extraFBOs_[0], { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0);
|
||||
int fbo_w, fbo_h;
|
||||
draw_->GetFramebufferDimensions(extraFBOs_[0], &fbo_w, &fbo_h);
|
||||
SetViewport2D(0, 0, fbo_w, fbo_h);
|
||||
draw_->SetScissorRect(0, 0, fbo_w, fbo_h);
|
||||
PostShaderUniforms uniforms{};
|
||||
int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
|
||||
int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
|
||||
presentation_->CalculatePostShaderUniforms(actualWidth, actualHeight, renderWidth_, renderHeight_, textureCache_->VideoIsPlaying(), &uniforms);
|
||||
BindPostShader(uniforms);
|
||||
DrawTextureFlags drawFlags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, 0.0f, 0.0f, 1.0f, 1.0f, ROTATION_LOCKED_HORIZONTAL, drawFlags);
|
||||
|
||||
// Use the extra FBO, with applied post-processing shader, as a texture.
|
||||
// fbo_bind_as_texture(extraFBOs_[0], FB_COLOR_BIT, 0);
|
||||
if (extraFBOs_.size() == 0) {
|
||||
ERROR_LOG(FRAMEBUF, "Unexpected: No extra FBOs?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (postShaderIsUpscalingFilter_) {
|
||||
flags |= OutputFlags::NEAREST;
|
||||
}
|
||||
|
||||
presentation_->SourceFramebuffer(extraFBOs_[0]);
|
||||
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1);
|
||||
} else {
|
||||
shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0);
|
||||
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
|
||||
// We are doing the DrawActiveTexture call directly to the backbuffer here. Hence, we must
|
||||
// flip V.
|
||||
if (needBackBufferYSwap_)
|
||||
std::swap(v0, v1);
|
||||
DrawTextureFlags flags2 = (!postShaderIsUpscalingFilter_ && g_Config.iBufFilter == SCALE_LINEAR) ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags2 = flags2 | DRAWTEX_TO_BACKBUFFER;
|
||||
|
||||
PostShaderUniforms uniforms{};
|
||||
int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
|
||||
int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
|
||||
presentation_->CalculatePostShaderUniforms(actualWidth, actualHeight, vfb->renderWidth, vfb->renderHeight, textureCache_->VideoIsPlaying(), &uniforms);
|
||||
BindPostShader(uniforms);
|
||||
if (g_Config.bEnableCardboardVR) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags2 | DRAWTEX_KEEP_TEX);
|
||||
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags2);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags2);
|
||||
}
|
||||
// DrawActiveTexture reverses these, probably to match "up".
|
||||
// TODO: Maybe use a flag instead.
|
||||
if (GetGPUBackend() == GPUBackend::DIRECT3D9 || GetGPUBackend() == GPUBackend::DIRECT3D11) {
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
presentation_->SourceFramebuffer(vfb->fbo);
|
||||
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1, uniforms);
|
||||
} else if (useBufferedRendering_) {
|
||||
WARN_LOG(FRAMEBUF, "Current VFB lacks an FBO: %08x", vfb->fb_address);
|
||||
}
|
||||
|
||||
// This may get called mid-draw if the game uses an immediate flip.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE);
|
||||
// PresentationCommon sets all kinds of state, we can't rely on anything.
|
||||
gstate_c.Dirty(DIRTY_ALL);
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DecimateFBOs() {
|
||||
|
|
|
@ -313,10 +313,8 @@ protected:
|
|||
virtual void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) = 0;
|
||||
virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) = 0;
|
||||
virtual void Bind2DShader() = 0;
|
||||
virtual void BindPostShader(const PostShaderUniforms &uniforms) = 0;
|
||||
|
||||
bool UpdateSize();
|
||||
void SetNumExtraFBOs(int num);
|
||||
|
||||
void FlushBeforeCopy();
|
||||
virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra
|
||||
|
@ -385,8 +383,6 @@ protected:
|
|||
u32 framebufRangeEnd_ = 0;
|
||||
|
||||
bool useBufferedRendering_ = false;
|
||||
bool usePostShader_ = false;
|
||||
bool postShaderAtOutputResolution_ = false;
|
||||
bool postShaderIsUpscalingFilter_ = false;
|
||||
int postShaderSSAAFilterLevel_ = 0;
|
||||
|
||||
|
@ -402,9 +398,6 @@ protected:
|
|||
int pixelHeight_;
|
||||
int bloomHack_ = 0;
|
||||
|
||||
// Used by post-processing shaders
|
||||
std::vector<Draw::Framebuffer *> extraFBOs_;
|
||||
|
||||
bool needGLESRebinds_ = false;
|
||||
|
||||
struct TempFBOInfo {
|
||||
|
|
|
@ -17,15 +17,20 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include "base/display.h"
|
||||
#include "base/timeutil.h"
|
||||
#include "file/vfs.h"
|
||||
#include "file/zip_read.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/HLE/sceDisplay.h"
|
||||
#include "GPU/Common/PostShader.h"
|
||||
#include "GPU/Common/PresentationCommon.h"
|
||||
#include "GPU/Common/ShaderTranslation.h"
|
||||
|
||||
struct Vertex {
|
||||
float x, y, z;
|
||||
|
@ -133,11 +138,11 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin
|
|||
cardboardSettings->screenHeight = cardboardScreenHeight;
|
||||
}
|
||||
|
||||
void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight, bool hasVideo, PostShaderUniforms *uniforms) {
|
||||
void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, bool hasVideo, PostShaderUniforms *uniforms) {
|
||||
float u_delta = 1.0f / bufferWidth;
|
||||
float v_delta = 1.0f / bufferHeight;
|
||||
float u_pixel_delta = 1.0f / renderWidth;
|
||||
float v_pixel_delta = 1.0f / renderHeight;
|
||||
float u_pixel_delta = 1.0f / renderWidth_;
|
||||
float v_pixel_delta = 1.0f / renderHeight_;
|
||||
if (postShaderAtOutputResolution_) {
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
|
||||
|
@ -154,6 +159,106 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer
|
|||
uniforms->pixelDelta[1] = v_pixel_delta;
|
||||
memcpy(uniforms->time, time, 4 * sizeof(float));
|
||||
uniforms->video = hasVideo;
|
||||
|
||||
// The shader translator tacks this onto our shaders, if we don't set it they render garbage.
|
||||
uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f;
|
||||
uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f;
|
||||
}
|
||||
|
||||
static std::string ReadShaderSrc(const std::string &filename) {
|
||||
size_t sz = 0;
|
||||
char *data = (char *)VFSReadFile(filename.c_str(), &sz);
|
||||
if (!data)
|
||||
return "";
|
||||
|
||||
std::string src(data, sz);
|
||||
free(data);
|
||||
return src;
|
||||
}
|
||||
|
||||
// Note: called on resize and settings changes.
|
||||
bool PresentationCommon::UpdatePostShader() {
|
||||
const ShaderInfo *shaderInfo = nullptr;
|
||||
if (g_Config.sPostShaderName != "Off") {
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
}
|
||||
|
||||
DestroyPostShader();
|
||||
if (shaderInfo == nullptr)
|
||||
return false;
|
||||
|
||||
std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile);
|
||||
std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile);
|
||||
if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string vsError, fsError;
|
||||
Draw::ShaderModule *vs = CompileShaderModule(Draw::ShaderStage::VERTEX, GLSL_140, vsSourceGLSL, &vsError);
|
||||
Draw::ShaderModule *fs = CompileShaderModule(Draw::ShaderStage::FRAGMENT, GLSL_140, fsSourceGLSL, &fsError);
|
||||
|
||||
// Don't worry, CompileShaderModule makes sure they get freed if one succeeded.
|
||||
if (!fs || !vs) {
|
||||
std::string errorString = vsError + "\n" + fsError;
|
||||
// DO NOT turn this into a report, as it will pollute our logs with all kinds of
|
||||
// user shader experiments.
|
||||
ERROR_LOG(FRAMEBUF, "Failed to build post-processing program from %s and %s!\n%s", shaderInfo->vertexShaderFile.c_str(), shaderInfo->fragmentShaderFile.c_str(), errorString.c_str());
|
||||
ShowPostShaderError(errorString);
|
||||
return false;
|
||||
}
|
||||
|
||||
Draw::UniformBufferDesc postShaderDesc{ sizeof(PostShaderUniforms), {
|
||||
{ "gl_HalfPixel", 0, -1, Draw::UniformType::FLOAT4, offsetof(PostShaderUniforms, gl_HalfPixel) },
|
||||
{ "u_texelDelta", 1, 1, Draw::UniformType::FLOAT2, offsetof(PostShaderUniforms, texelDelta) },
|
||||
{ "u_pixelDelta", 2, 2, Draw::UniformType::FLOAT2, offsetof(PostShaderUniforms, pixelDelta) },
|
||||
{ "u_time", 3, 3, Draw::UniformType::FLOAT4, offsetof(PostShaderUniforms, time) },
|
||||
{ "u_video", 4, 4, Draw::UniformType::FLOAT1, offsetof(PostShaderUniforms, video) },
|
||||
} };
|
||||
Draw::Pipeline *pipeline = CreatePipeline({ vs, fs }, true, &postShaderDesc);
|
||||
if (!pipeline)
|
||||
return false;
|
||||
|
||||
// No depth/stencil for post processing
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ (int)renderWidth_, (int)renderHeight_, 1, 1, false, Draw::FBO_8888 });
|
||||
if (fbo)
|
||||
postShaderFramebuffers_.push_back(fbo);
|
||||
|
||||
usePostShader_ = true;
|
||||
postShaderPipelines_.push_back(pipeline);
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
postShaderIsUpscalingFilter_ = shaderInfo->isUpscalingFilter;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PresentationCommon::ShowPostShaderError(const std::string &errorString) {
|
||||
// let's show the first line of the error string as an OSM.
|
||||
std::set<std::string> blacklistedLines;
|
||||
// These aren't useful to show, skip to the first interesting line.
|
||||
blacklistedLines.insert("Fragment shader failed to compile with the following errors:");
|
||||
blacklistedLines.insert("Vertex shader failed to compile with the following errors:");
|
||||
blacklistedLines.insert("Compile failed.");
|
||||
blacklistedLines.insert("");
|
||||
|
||||
std::string firstLine;
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < errorString.size(); i++) {
|
||||
if (errorString[i] == '\n' && i == start) {
|
||||
start = i + 1;
|
||||
} else if (errorString[i] == '\n') {
|
||||
firstLine = errorString.substr(start, i - start);
|
||||
if (blacklistedLines.find(firstLine) == blacklistedLines.end()) {
|
||||
break;
|
||||
}
|
||||
start = i + 1;
|
||||
firstLine.clear();
|
||||
}
|
||||
}
|
||||
if (!firstLine.empty()) {
|
||||
host->NotifyUserMessage("Post-shader error: " + firstLine + "...", 10.0f, 0xFF3090FF);
|
||||
} else {
|
||||
host->NotifyUserMessage("Post-shader error, see log for details", 10.0f, 0xFF3090FF);
|
||||
}
|
||||
}
|
||||
|
||||
void PresentationCommon::UpdateShaderInfo(const ShaderInfo *shaderInfo) {
|
||||
|
@ -169,51 +274,61 @@ void PresentationCommon::DeviceRestore(Draw::DrawContext *draw) {
|
|||
CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void PresentationCommon::CreateDeviceObjects() {
|
||||
Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector<Draw::ShaderModule *> shaders, bool postShader, const Draw::UniformBufferDesc *uniformDesc) {
|
||||
using namespace Draw;
|
||||
|
||||
Semantic pos = SEM_POSITION;
|
||||
Semantic tc = SEM_TEXCOORD0;
|
||||
// Shader translation marks these both as "TEXCOORDs" on HLSL...
|
||||
if (postShader && (lang_ == HLSL_D3D11 || lang_ == HLSL_D3D11_LEVEL9 || lang_ == HLSL_DX9)) {
|
||||
pos = SEM_TEXCOORD0;
|
||||
tc = SEM_TEXCOORD1;
|
||||
}
|
||||
|
||||
// TODO: Maybe get rid of color0.
|
||||
InputLayoutDesc inputDesc = {
|
||||
{
|
||||
{ sizeof(Vertex), false },
|
||||
},
|
||||
{
|
||||
{ 0, SEM_POSITION, DataFormat::R32G32B32_FLOAT, 0 },
|
||||
{ 0, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 12 },
|
||||
{ 0, pos, DataFormat::R32G32B32_FLOAT, 0 },
|
||||
{ 0, tc, DataFormat::R32G32_FLOAT, 12 },
|
||||
{ 0, SEM_COLOR0, DataFormat::R8G8B8A8_UNORM, 20 },
|
||||
},
|
||||
};
|
||||
|
||||
vdata_ = draw_->CreateBuffer(sizeof(Vertex) * 4, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
|
||||
// TODO: Use 4 and a strip? shorts?
|
||||
idata_ = draw_->CreateBuffer(sizeof(int) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA);
|
||||
|
||||
InputLayout *inputLayout = draw_->CreateInputLayout(inputDesc);
|
||||
DepthStencilState *depth = draw_->CreateDepthStencilState({ false, false, Comparison::LESS });
|
||||
BlendState *blendstateOff = draw_->CreateBlendState({ false, 0xF });
|
||||
RasterState *rasterNoCull = draw_->CreateRasterState({});
|
||||
|
||||
samplerNearest_ = draw_->CreateSamplerState({ TextureFilter::NEAREST, TextureFilter::NEAREST, TextureFilter::NEAREST });
|
||||
samplerLinear_ = draw_->CreateSamplerState({ TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR });
|
||||
|
||||
PipelineDesc pipelineDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ draw_->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw_->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
|
||||
inputLayout, depth, blendstateOff, rasterNoCull, &vsTexColBufDesc
|
||||
};
|
||||
texColor_ = draw_->CreateGraphicsPipeline(pipelineDesc);
|
||||
|
||||
PipelineDesc pipelineDescRBSwizzle{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ draw_->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw_->GetFshaderPreset(FS_TEXTURE_COLOR_2D_RB_SWIZZLE) },
|
||||
inputLayout, depth, blendstateOff, rasterNoCull, &vsTexColBufDesc
|
||||
};
|
||||
texColorRBSwizzle_ = draw_->CreateGraphicsPipeline(pipelineDescRBSwizzle);
|
||||
PipelineDesc pipelineDesc{ Primitive::TRIANGLE_LIST, shaders, inputLayout, depth, blendstateOff, rasterNoCull, uniformDesc };
|
||||
Pipeline *pipeline = draw_->CreateGraphicsPipeline(pipelineDesc);
|
||||
|
||||
inputLayout->Release();
|
||||
depth->Release();
|
||||
blendstateOff->Release();
|
||||
rasterNoCull->Release();
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void PresentationCommon::CreateDeviceObjects() {
|
||||
using namespace Draw;
|
||||
|
||||
vdata_ = draw_->CreateBuffer(sizeof(Vertex) * 4, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
|
||||
// TODO: Use 4 and a strip? shorts?
|
||||
idata_ = draw_->CreateBuffer(sizeof(int) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA);
|
||||
|
||||
samplerNearest_ = draw_->CreateSamplerState({ TextureFilter::NEAREST, TextureFilter::NEAREST, TextureFilter::NEAREST });
|
||||
samplerLinear_ = draw_->CreateSamplerState({ TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR });
|
||||
|
||||
texColor_ = CreatePipeline({ draw_->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw_->GetFshaderPreset(FS_TEXTURE_COLOR_2D) }, false, &vsTexColBufDesc);
|
||||
texColorRBSwizzle_ = CreatePipeline({ draw_->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw_->GetFshaderPreset(FS_TEXTURE_COLOR_2D_RB_SWIZZLE) }, false, &vsTexColBufDesc);
|
||||
|
||||
if (restorePostShader_)
|
||||
UpdatePostShader();
|
||||
restorePostShader_ = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -223,6 +338,13 @@ static void DoRelease(T *&obj) {
|
|||
obj = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void DoReleaseVector(std::vector<T *> &list) {
|
||||
for (auto &obj : list)
|
||||
obj->Release();
|
||||
list.clear();
|
||||
}
|
||||
|
||||
void PresentationCommon::DestroyDeviceObjects() {
|
||||
DoRelease(texColor_);
|
||||
DoRelease(texColorRBSwizzle_);
|
||||
|
@ -232,6 +354,57 @@ void PresentationCommon::DestroyDeviceObjects() {
|
|||
DoRelease(idata_);
|
||||
DoRelease(srcTexture_);
|
||||
DoRelease(srcFramebuffer_);
|
||||
|
||||
DestroyPostShader();
|
||||
}
|
||||
|
||||
void PresentationCommon::DestroyPostShader() {
|
||||
restorePostShader_ = usePostShader_;
|
||||
usePostShader_ = false;
|
||||
|
||||
DoReleaseVector(postShaderModules_);
|
||||
DoReleaseVector(postShaderPipelines_);
|
||||
DoReleaseVector(postShaderFramebuffers_);
|
||||
}
|
||||
|
||||
Draw::ShaderModule *PresentationCommon::CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) {
|
||||
std::string translated = src;
|
||||
bool translationFailed = false;
|
||||
if (lang != lang_) {
|
||||
// Gonna have to upconvert the shader.
|
||||
if (!TranslateShader(&translated, lang_, nullptr, src, lang, stage, errorString)) {
|
||||
ERROR_LOG(FRAMEBUF, "Failed to translate post-shader: %s", errorString->c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Draw::ShaderLanguage mappedLang;
|
||||
// These aren't exact, unfortunately, but we just need the type Draw will accept.
|
||||
switch (lang_) {
|
||||
case GLSL_140:
|
||||
mappedLang = Draw::ShaderLanguage::GLSL_ES_200;
|
||||
break;
|
||||
case GLSL_300:
|
||||
mappedLang = Draw::ShaderLanguage::GLSL_410;
|
||||
break;
|
||||
case GLSL_VULKAN:
|
||||
mappedLang = Draw::ShaderLanguage::GLSL_VULKAN;
|
||||
break;
|
||||
case HLSL_DX9:
|
||||
mappedLang = Draw::ShaderLanguage::HLSL_D3D9;
|
||||
break;
|
||||
case HLSL_D3D11:
|
||||
case HLSL_D3D11_LEVEL9:
|
||||
mappedLang = Draw::ShaderLanguage::HLSL_D3D11;
|
||||
break;
|
||||
default:
|
||||
mappedLang = Draw::ShaderLanguage::GLSL_ES_200;
|
||||
break;
|
||||
}
|
||||
Draw::ShaderModule *shader = draw_->CreateShaderModule(stage, mappedLang, (const uint8_t *)translated.c_str(), translated.size(), "postshader");
|
||||
if (shader)
|
||||
postShaderModules_.push_back(shader);
|
||||
return shader;
|
||||
}
|
||||
|
||||
void PresentationCommon::SourceTexture(Draw::Texture *texture) {
|
||||
|
@ -250,17 +423,70 @@ void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb) {
|
|||
srcFramebuffer_ = fb;
|
||||
}
|
||||
|
||||
void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) {
|
||||
void PresentationCommon::BindSource() {
|
||||
if (srcTexture_) {
|
||||
draw_->BindTexture(0, srcTexture_);
|
||||
} else if (srcFramebuffer_) {
|
||||
draw_->BindFramebufferAsTexture(srcFramebuffer_, 0, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1, const PostShaderUniforms &uniforms) {
|
||||
// Make sure Direct3D 11 clears state, since we set shaders outside Draw.
|
||||
draw_->BindPipeline(nullptr);
|
||||
|
||||
// TODO: If shader objects have been created by now, we might have received errors.
|
||||
// GLES can have the shader fail later, shader->failed / shader->error.
|
||||
// This should auto-disable usePostShader_ and call ShowPostShaderError().
|
||||
|
||||
bool useNearest = flags & OutputFlags::NEAREST;
|
||||
bool usePostShader = usePostShader_ && !(flags & OutputFlags::RB_SWIZZLE);
|
||||
|
||||
if (usePostShader && postShaderFramebuffers_.size() == 1 && !postShaderAtOutputResolution_) {
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffers_[0], { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
BindSource();
|
||||
|
||||
int fbo_w, fbo_h;
|
||||
draw_->GetFramebufferDimensions(postShaderFramebuffers_[0], &fbo_w, &fbo_h);
|
||||
Draw::Viewport viewport{ 0, 0, (float)fbo_w, (float)fbo_h, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
draw_->SetScissorRect(0, 0, fbo_w, fbo_h);
|
||||
|
||||
draw_->BindPipeline(postShaderPipelines_.front());
|
||||
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
|
||||
Draw::SamplerState *sampler = useNearest ? samplerNearest_ : samplerLinear_;
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
Vertex verts[4] = {
|
||||
{ -1, -1, 0, 0, 1, 0xFFFFFFFF }, // TL
|
||||
{ -1, 1, 0, 0, 0, 0xFFFFFFFF }, // BL
|
||||
{ 1, 1, 0, 1, 0, 0xFFFFFFFF }, // BR
|
||||
{ 1, -1, 0, 1, 1, 0xFFFFFFFF }, // TR
|
||||
};
|
||||
|
||||
draw_->UpdateBuffer(vdata_, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD);
|
||||
|
||||
int indexes[] = { 0, 1, 2, 0, 2, 3 };
|
||||
draw_->UpdateBuffer(idata_, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD);
|
||||
|
||||
draw_->BindVertexBuffers(0, 1, &vdata_, nullptr);
|
||||
draw_->BindIndexBuffer(idata_, 0);
|
||||
draw_->DrawIndexed(6, 0);
|
||||
draw_->BindIndexBuffer(nullptr, 0);
|
||||
}
|
||||
|
||||
if (postShaderIsUpscalingFilter_)
|
||||
useNearest = true;
|
||||
|
||||
CardboardSettings cardboardSettings;
|
||||
GetCardboardSettings(&cardboardSettings);
|
||||
|
||||
Draw::Pipeline *pipeline = flags & OutputFlags::RB_SWIZZLE ? texColorRBSwizzle_ : texColor_;
|
||||
|
||||
Draw::SamplerState *sampler;
|
||||
if (flags & OutputFlags::NEAREST) {
|
||||
sampler = samplerNearest_;
|
||||
} else {
|
||||
sampler = samplerLinear_;
|
||||
if (usePostShader && postShaderAtOutputResolution_) {
|
||||
pipeline = postShaderPipelines_.front();
|
||||
}
|
||||
|
||||
// These are the output coordinates.
|
||||
|
@ -269,7 +495,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
|
||||
if (GetGPUBackend() == GPUBackend::DIRECT3D9) {
|
||||
x -= 0.5f;
|
||||
// TODO: This is plus because of some flipping going on, I think? Investigate...
|
||||
// This is plus because the top is larger y.
|
||||
y += 0.5f;
|
||||
}
|
||||
|
||||
|
@ -280,7 +506,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
Vertex verts[4] = {
|
||||
{ x, y, 0, u0, v0, 0xFFFFFFFF }, // TL
|
||||
{ x, y + h, 0, u0, v1, 0xFFFFFFFF }, // BL
|
||||
{ x + w, y + h, 0, u1, v1, 0xFFFFFFFF }, // BR
|
||||
{ x + w, y + h, 0, u1, v1, 0xFFFFFFFF }, // BR
|
||||
{ x + w, y, 0, u1, v0, 0xFFFFFFFF }, // TR
|
||||
};
|
||||
|
||||
|
@ -327,24 +553,26 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
|
||||
|
||||
if (srcTexture_) {
|
||||
draw_->BindTexture(0, srcTexture_);
|
||||
} else if (srcFramebuffer_) {
|
||||
draw_->BindFramebufferAsTexture(srcFramebuffer_, 0, Draw::FB_COLOR_BIT, 0);
|
||||
if (usePostShader && !postShaderFramebuffers_.empty() && !postShaderAtOutputResolution_) {
|
||||
draw_->BindFramebufferAsTexture(postShaderFramebuffers_.back(), 0, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
assert(false);
|
||||
BindSource();
|
||||
}
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
Draw::VsTexColUB ub{};
|
||||
memcpy(ub.WorldViewProj, g_display_rot_matrix.m, sizeof(float) * 16);
|
||||
// Make sure Direct3D 11 clears state, since we set shaders outside Draw.
|
||||
draw_->BindPipeline(nullptr);
|
||||
draw_->BindPipeline(pipeline);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
if (usePostShader && postShaderAtOutputResolution_) {
|
||||
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
} else {
|
||||
Draw::VsTexColUB ub{};
|
||||
memcpy(ub.WorldViewProj, g_display_rot_matrix.m, sizeof(float) * 16);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
}
|
||||
draw_->BindVertexBuffers(0, 1, &vdata_, nullptr);
|
||||
draw_->BindIndexBuffer(idata_, 0);
|
||||
|
||||
Draw::SamplerState *sampler = useNearest ? samplerNearest_ : samplerLinear_;
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
auto setViewport = [&](float x, float y, float w, float h) {
|
||||
Draw::Viewport viewport{ x, y, w, h, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
|
||||
struct CardboardSettings {
|
||||
bool enabled;
|
||||
float leftEyeXPosition;
|
||||
|
@ -29,7 +31,9 @@ struct CardboardSettings {
|
|||
struct PostShaderUniforms {
|
||||
float texelDelta[2]; float pixelDelta[2];
|
||||
float time[4];
|
||||
float video;
|
||||
float video; float pad[3];
|
||||
// Used on Direct3D9.
|
||||
float gl_HalfPixel[4];
|
||||
};
|
||||
|
||||
void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH, int rotation);
|
||||
|
@ -40,6 +44,7 @@ class DrawContext;
|
|||
class Framebuffer;
|
||||
class Pipeline;
|
||||
class SamplerState;
|
||||
class ShaderModule;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
|
@ -69,26 +74,40 @@ public:
|
|||
PresentationCommon(Draw::DrawContext *draw);
|
||||
~PresentationCommon();
|
||||
|
||||
void UpdateSize(int w, int h) {
|
||||
void UpdateSize(int w, int h, int rw, int rh) {
|
||||
pixelWidth_ = w;
|
||||
pixelHeight_ = h;
|
||||
renderWidth_ = rw;
|
||||
renderHeight_ = rh;
|
||||
}
|
||||
void SetLanguage(ShaderLanguage lang) {
|
||||
lang_ = lang;
|
||||
}
|
||||
|
||||
bool UpdatePostShader();
|
||||
void UpdateShaderInfo(const ShaderInfo *shaderInfo);
|
||||
|
||||
void DeviceLost();
|
||||
void DeviceRestore(Draw::DrawContext *draw);
|
||||
|
||||
void GetCardboardSettings(CardboardSettings *cardboardSettings);
|
||||
void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight, bool hasVideo, PostShaderUniforms *uniforms);
|
||||
void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, bool hasVideo, PostShaderUniforms *uniforms);
|
||||
|
||||
// TODO: Cleanup
|
||||
void SourceTexture(Draw::Texture *texture);
|
||||
void SourceFramebuffer(Draw::Framebuffer *fb);
|
||||
void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1);
|
||||
void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1, const PostShaderUniforms &uniforms);
|
||||
|
||||
protected:
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
void DestroyPostShader();
|
||||
|
||||
void ShowPostShaderError(const std::string &errorString);
|
||||
|
||||
Draw::ShaderModule *CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString);
|
||||
Draw::Pipeline *CreatePipeline(std::vector<Draw::ShaderModule *> shaders, bool postShader, const Draw::UniformBufferDesc *uniformDesc);
|
||||
|
||||
void BindSource();
|
||||
|
||||
Draw::DrawContext *draw_;
|
||||
Draw::Pipeline *texColor_ = nullptr;
|
||||
|
@ -98,10 +117,21 @@ protected:
|
|||
Draw::Buffer *vdata_ = nullptr;
|
||||
Draw::Buffer *idata_ = nullptr;
|
||||
|
||||
std::vector<Draw::ShaderModule *> postShaderModules_;
|
||||
std::vector<Draw::Pipeline *> postShaderPipelines_;
|
||||
std::vector<Draw::Framebuffer *> postShaderFramebuffers_;
|
||||
|
||||
Draw::Texture *srcTexture_ = nullptr;
|
||||
Draw::Framebuffer *srcFramebuffer_ = nullptr;
|
||||
|
||||
int pixelWidth_ = 0;
|
||||
int pixelHeight_ = 0;
|
||||
int renderWidth_ = 0;
|
||||
int renderHeight_ = 0;
|
||||
|
||||
bool usePostShader_ = false;
|
||||
bool restorePostShader_ = false;
|
||||
bool postShaderAtOutputResolution_ = false;
|
||||
bool postShaderIsUpscalingFilter_ = false;
|
||||
ShaderLanguage lang_;
|
||||
};
|
||||
|
|
|
@ -87,13 +87,6 @@ const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11::g_QuadVertexElements[2]
|
|||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, },
|
||||
};
|
||||
|
||||
// The current simple shader translator outputs everything as semantic texcoords, so let's just play along
|
||||
// for simplicity.
|
||||
const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11::g_PostVertexElements[2] = {
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, },
|
||||
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 12, },
|
||||
};
|
||||
|
||||
FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
|
||||
: FramebufferManagerCommon(draw) {
|
||||
device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
|
||||
|
@ -124,10 +117,6 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
|
|||
vb.Usage = D3D11_USAGE_DYNAMIC;
|
||||
vb.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &quadBuffer_));
|
||||
vb.ByteWidth = ROUND_UP(sizeof(PostShaderUniforms), 16);
|
||||
vb.Usage = D3D11_USAGE_DYNAMIC;
|
||||
vb.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &postConstants_));
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc{};
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
@ -146,7 +135,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
|
|||
|
||||
ShaderTranslationInit();
|
||||
|
||||
CompilePostShader();
|
||||
presentation_->SetLanguage(HLSL_D3D11);
|
||||
}
|
||||
|
||||
FramebufferManagerD3D11::~FramebufferManagerD3D11() {
|
||||
|
@ -160,23 +149,12 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() {
|
|||
quadInputLayout_->Release();
|
||||
quadBuffer_->Release();
|
||||
fsQuadBuffer_->Release();
|
||||
postConstants_->Release();
|
||||
|
||||
if (drawPixelsTex_)
|
||||
drawPixelsTex_->Release();
|
||||
if (drawPixelsTexView_)
|
||||
drawPixelsTexView_->Release();
|
||||
|
||||
if (postVertexShader_) {
|
||||
postVertexShader_->Release();
|
||||
}
|
||||
if (postPixelShader_) {
|
||||
postPixelShader_->Release();
|
||||
}
|
||||
if (postInputLayout_) {
|
||||
postInputLayout_->Release();
|
||||
}
|
||||
|
||||
// Temp FBOs cleared by FramebufferCommon.
|
||||
delete[] convBuf;
|
||||
|
||||
|
@ -215,74 +193,6 @@ void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) {
|
|||
drawEngine_ = td;
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::CompilePostShader() {
|
||||
std::string vsSource;
|
||||
std::string psSource;
|
||||
|
||||
if (postVertexShader_) {
|
||||
postVertexShader_->Release();
|
||||
postVertexShader_ = nullptr;
|
||||
}
|
||||
if (postPixelShader_) {
|
||||
postPixelShader_->Release();
|
||||
postPixelShader_ = nullptr;
|
||||
}
|
||||
if (postInputLayout_) {
|
||||
postInputLayout_->Release();
|
||||
postInputLayout_ = nullptr;
|
||||
}
|
||||
|
||||
const ShaderInfo *shaderInfo = nullptr;
|
||||
if (g_Config.sPostShaderName == "Off") {
|
||||
usePostShader_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
usePostShader_ = false;
|
||||
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
if (shaderInfo) {
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
presentation_->UpdateShaderInfo(shaderInfo);
|
||||
size_t sz;
|
||||
char *vs = (char *)VFSReadFile(shaderInfo->vertexShaderFile.c_str(), &sz);
|
||||
if (!vs)
|
||||
return;
|
||||
char *ps = (char *)VFSReadFile(shaderInfo->fragmentShaderFile.c_str(), &sz);
|
||||
if (!ps) {
|
||||
free(vs);
|
||||
return;
|
||||
}
|
||||
std::string vsSourceGLSL = vs;
|
||||
std::string psSourceGLSL = ps;
|
||||
free(vs);
|
||||
free(ps);
|
||||
TranslatedShaderMetadata metaVS, metaFS;
|
||||
std::string errorVS, errorFS;
|
||||
if (!TranslateShader(&vsSource, HLSL_D3D11, &metaVS, vsSourceGLSL, GLSL_140, Draw::ShaderStage::VERTEX, &errorVS))
|
||||
return;
|
||||
if (!TranslateShader(&psSource, HLSL_D3D11, &metaFS, psSourceGLSL, GLSL_140, Draw::ShaderStage::FRAGMENT, &errorFS))
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
|
||||
std::vector<uint8_t> byteCode;
|
||||
postVertexShader_ = CreateVertexShaderD3D11(device_, vsSource.data(), vsSource.size(), &byteCode, featureLevel_, flags);
|
||||
if (!postVertexShader_) {
|
||||
return;
|
||||
}
|
||||
postPixelShader_ = CreatePixelShaderD3D11(device_, psSource.data(), psSource.size(), featureLevel_, flags);
|
||||
if (!postPixelShader_) {
|
||||
postVertexShader_->Release();
|
||||
return;
|
||||
}
|
||||
ASSERT_SUCCESS(device_->CreateInputLayout(g_PostVertexElements, 2, byteCode.data(), byteCode.size(), &postInputLayout_));
|
||||
usePostShader_ = true;
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
|
||||
if (drawPixelsTex_ && (drawPixelsTexW_ != width || drawPixelsTexH_ != height)) {
|
||||
|
@ -422,33 +332,6 @@ void FramebufferManagerD3D11::Bind2DShader() {
|
|||
context_->VSSetShader(quadVertexShader_, 0, 0);
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::BindPostShader(const PostShaderUniforms &uniforms) {
|
||||
if (!postPixelShader_) {
|
||||
if (usePostShader_) {
|
||||
CompilePostShader();
|
||||
}
|
||||
if (!usePostShader_) {
|
||||
SetNumExtraFBOs(0);
|
||||
context_->IASetInputLayout(quadInputLayout_);
|
||||
context_->PSSetShader(quadPixelShader_, 0, 0);
|
||||
context_->VSSetShader(quadVertexShader_, 0, 0);
|
||||
return;
|
||||
} else {
|
||||
SetNumExtraFBOs(1);
|
||||
}
|
||||
}
|
||||
context_->IASetInputLayout(postInputLayout_);
|
||||
context_->PSSetShader(postPixelShader_, 0, 0);
|
||||
context_->VSSetShader(postVertexShader_, 0, 0);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
ASSERT_SUCCESS(context_->Map(postConstants_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
|
||||
memcpy(map.pData, &uniforms, sizeof(uniforms));
|
||||
context_->Unmap(postConstants_, 0);
|
||||
context_->VSSetConstantBuffers(0, 1, &postConstants_); // Probably not necessary
|
||||
context_->PSSetConstantBuffers(0, 1, &postConstants_);
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) {
|
||||
if (!useBufferedRendering_ || !vfb->fbo) {
|
||||
return;
|
||||
|
@ -718,8 +601,6 @@ void FramebufferManagerD3D11::DestroyAllFBOs() {
|
|||
tempFB.second.fbo->Release();
|
||||
}
|
||||
tempFBOs_.clear();
|
||||
|
||||
SetNumExtraFBOs(0);
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::Resized() {
|
||||
|
@ -730,5 +611,5 @@ void FramebufferManagerD3D11::Resized() {
|
|||
}
|
||||
|
||||
// Might have a new post shader - let's compile it.
|
||||
CompilePostShader();
|
||||
presentation_->UpdatePostShader();
|
||||
}
|
||||
|
|
|
@ -68,8 +68,6 @@ protected:
|
|||
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
|
||||
|
||||
private:
|
||||
void CompilePostShader();
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
void Bind2DShader() override;
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
|
@ -116,9 +114,5 @@ private:
|
|||
|
||||
// Used by post-processing shader
|
||||
// Postprocessing
|
||||
ID3D11VertexShader *postVertexShader_ = nullptr;
|
||||
ID3D11PixelShader *postPixelShader_ = nullptr;
|
||||
ID3D11InputLayout *postInputLayout_ = nullptr;
|
||||
ID3D11Buffer *postConstants_ = nullptr;
|
||||
static const D3D11_INPUT_ELEMENT_DESC g_PostVertexElements[2];
|
||||
};
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include "gfx/d3d9_state.h"
|
||||
#include "GPU/Common/FramebufferCommon.h"
|
||||
#include "GPU/Common/PresentationCommon.h"
|
||||
#include "GPU/Common/ShaderTranslation.h"
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
#include "GPU/Directx9/FramebufferDX9.h"
|
||||
#include "GPU/Directx9/ShaderManagerDX9.h"
|
||||
|
@ -112,6 +114,10 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
nullTex_->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD);
|
||||
memset(rect.pBits, 0, 4);
|
||||
nullTex_->UnlockRect(0);
|
||||
|
||||
ShaderTranslationInit();
|
||||
|
||||
presentation_->SetLanguage(HLSL_DX9);
|
||||
}
|
||||
|
||||
FramebufferManagerDX9::~FramebufferManagerDX9() {
|
||||
|
@ -307,10 +313,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
device_->SetVertexShader(pFramebufferVertexShader);
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::BindPostShader(const PostShaderUniforms &uniforms) {
|
||||
Bind2DShader();
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) {
|
||||
if (!useBufferedRendering_ || !vfb->fbo) {
|
||||
return;
|
||||
|
@ -702,8 +704,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
it.second.surface->Release();
|
||||
}
|
||||
offscreenSurfaces_.clear();
|
||||
|
||||
SetNumExtraFBOs(0);
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::Resized() {
|
||||
|
@ -712,6 +712,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
if (UpdateSize()) {
|
||||
DestroyAllFBOs();
|
||||
}
|
||||
presentation_->UpdatePostShader();
|
||||
}
|
||||
|
||||
bool FramebufferManagerDX9::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat fb_format, GPUDebugBuffer &buffer, int maxRes) {
|
||||
|
|
|
@ -69,7 +69,6 @@ public:
|
|||
|
||||
protected:
|
||||
void Bind2DShader() override;
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
void DecimateFBOs() override;
|
||||
|
||||
// Used by ReadFramebufferToMemory and later framebuffer block copies
|
||||
|
|
|
@ -99,119 +99,6 @@ void FramebufferManagerGLES::CompileDraw2DProgram() {
|
|||
draw2dprogram_ = render_->CreateProgram(shaders, semantics, queries, initializers, false);
|
||||
for (auto shader : shaders)
|
||||
render_->DeleteShader(shader);
|
||||
CompilePostShader();
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::CompilePostShader() {
|
||||
SetNumExtraFBOs(0);
|
||||
const ShaderInfo *shaderInfo = 0;
|
||||
if (g_Config.sPostShaderName != "Off") {
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
}
|
||||
|
||||
if (shaderInfo) {
|
||||
std::string errorString;
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
presentation_->UpdateShaderInfo(shaderInfo);
|
||||
|
||||
size_t sz;
|
||||
char *vs = (char *)VFSReadFile(shaderInfo->vertexShaderFile.c_str(), &sz);
|
||||
if (!vs)
|
||||
return;
|
||||
char *fs = (char *)VFSReadFile(shaderInfo->fragmentShaderFile.c_str(), &sz);
|
||||
if (!fs) {
|
||||
free(vs);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string vshader;
|
||||
std::string fshader;
|
||||
bool translationFailed = false;
|
||||
if (gl_extensions.IsCoreContext) {
|
||||
// Gonna have to upconvert the shaders.
|
||||
if (!TranslateShader(&vshader, GLSL_300, nullptr, vs, GLSL_140, Draw::ShaderStage::VERTEX, &errorString)) {
|
||||
translationFailed = true;
|
||||
ELOG("Failed to translate post-vshader: %s", errorString.c_str());
|
||||
}
|
||||
if (!TranslateShader(&fshader, GLSL_300, nullptr, fs, GLSL_140, Draw::ShaderStage::FRAGMENT, &errorString)) {
|
||||
translationFailed = true;
|
||||
ELOG("Failed to translate post-fshader: %s", errorString.c_str());
|
||||
}
|
||||
} else {
|
||||
vshader = vs;
|
||||
fshader = fs;
|
||||
}
|
||||
|
||||
if (!translationFailed) {
|
||||
SetNumExtraFBOs(1);
|
||||
|
||||
std::vector<GLRShader *> shaders;
|
||||
shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vshader, "postshader"));
|
||||
shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fshader, "postshader"));
|
||||
std::vector<GLRProgram::UniformLocQuery> queries;
|
||||
queries.push_back({ &u_postShaderTex, "tex" });
|
||||
queries.push_back({ &deltaLoc_, "u_texelDelta" });
|
||||
queries.push_back({ &pixelDeltaLoc_, "u_pixelDelta" });
|
||||
queries.push_back({ &timeLoc_, "u_time" });
|
||||
queries.push_back({ &videoLoc_, "u_video" });
|
||||
|
||||
std::vector<GLRProgram::Initializer> inits;
|
||||
inits.push_back({ &u_postShaderTex, 0, 0 });
|
||||
std::vector<GLRProgram::Semantic> semantics;
|
||||
semantics.push_back({ 0, "a_position" });
|
||||
semantics.push_back({ 1, "a_texcoord0" });
|
||||
postShaderProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false);
|
||||
postShaderModules_ = shaders;
|
||||
} else {
|
||||
ERROR_LOG(FRAMEBUF, "Failed to translate post shader!");
|
||||
}
|
||||
free(vs);
|
||||
free(fs);
|
||||
|
||||
if (!postShaderProgram_) {
|
||||
// DO NOT turn this into a report, as it will pollute our logs with all kinds of
|
||||
// user shader experiments.
|
||||
ERROR_LOG(FRAMEBUF, "Failed to build post-processing program from %s and %s!\n%s", shaderInfo->vertexShaderFile.c_str(), shaderInfo->fragmentShaderFile.c_str(), errorString.c_str());
|
||||
ShowPostShaderError(errorString);
|
||||
usePostShader_ = false;
|
||||
} else {
|
||||
usePostShader_ = true;
|
||||
}
|
||||
} else {
|
||||
postShaderProgram_ = nullptr;
|
||||
usePostShader_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::ShowPostShaderError(const std::string &errorString) {
|
||||
// let's show the first line of the error string as an OSM.
|
||||
std::set<std::string> blacklistedLines;
|
||||
// These aren't useful to show, skip to the first interesting line.
|
||||
blacklistedLines.insert("Fragment shader failed to compile with the following errors:");
|
||||
blacklistedLines.insert("Vertex shader failed to compile with the following errors:");
|
||||
blacklistedLines.insert("Compile failed.");
|
||||
blacklistedLines.insert("");
|
||||
|
||||
std::string firstLine;
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < errorString.size(); i++) {
|
||||
if (errorString[i] == '\n' && i == start) {
|
||||
start = i + 1;
|
||||
} else if (errorString[i] == '\n') {
|
||||
firstLine = errorString.substr(start, i - start);
|
||||
if (blacklistedLines.find(firstLine) == blacklistedLines.end()) {
|
||||
break;
|
||||
}
|
||||
start = i + 1;
|
||||
firstLine.clear();
|
||||
}
|
||||
}
|
||||
if (!firstLine.empty()) {
|
||||
host->NotifyUserMessage("Post-shader error: " + firstLine + "...", 10.0f, 0xFF3090FF);
|
||||
} else {
|
||||
host->NotifyUserMessage("Post-shader error, see log for details", 10.0f, 0xFF3090FF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,46 +106,6 @@ void FramebufferManagerGLES::Bind2DShader() {
|
|||
render_->BindProgram(draw2dprogram_);
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::BindPostShader(const PostShaderUniforms &uniforms) {
|
||||
// Make sure we've compiled the shader.
|
||||
if (!postShaderProgram_) {
|
||||
CompileDraw2DProgram();
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
std::string errorMessage;
|
||||
for (size_t i = 0; i < postShaderModules_.size(); ++i) {
|
||||
auto &shader = postShaderModules_[i];
|
||||
if (shader->failed) {
|
||||
failed = true;
|
||||
errorMessage += shader->error + "\n";
|
||||
}
|
||||
|
||||
if (shader->valid || shader->failed) {
|
||||
render_->DeleteShader(shader);
|
||||
postShaderModules_.erase(postShaderModules_.begin() + i);
|
||||
// Check this index again.
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
ShowPostShaderError(errorMessage);
|
||||
// Show stuff if possible in an upcoming frame.
|
||||
usePostShader_ = false;
|
||||
}
|
||||
|
||||
render_->BindProgram(postShaderProgram_);
|
||||
if (deltaLoc_ != -1)
|
||||
render_->SetUniformF(&deltaLoc_, 2, uniforms.texelDelta);
|
||||
if (pixelDeltaLoc_ != -1)
|
||||
render_->SetUniformF(&pixelDeltaLoc_, 2, uniforms.pixelDelta);
|
||||
if (timeLoc_ != -1)
|
||||
render_->SetUniformF(&timeLoc_, 4, uniforms.time);
|
||||
if (videoLoc_ != -1)
|
||||
render_->SetUniformF(&videoLoc_, 1, &uniforms.video);
|
||||
}
|
||||
|
||||
FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) :
|
||||
FramebufferManagerCommon(draw),
|
||||
render_(render)
|
||||
|
@ -267,6 +114,7 @@ FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRender
|
|||
needGLESRebinds_ = true;
|
||||
CreateDeviceObjects();
|
||||
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
presentation_->SetLanguage(gl_extensions.IsCoreContext ? GLSL_300 : GLSL_140);
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::Init() {
|
||||
|
@ -310,10 +158,6 @@ void FramebufferManagerGLES::DestroyDeviceObjects() {
|
|||
render_->DeleteProgram(draw2dprogram_);
|
||||
draw2dprogram_ = nullptr;
|
||||
}
|
||||
if (postShaderProgram_) {
|
||||
render_->DeleteProgram(postShaderProgram_);
|
||||
postShaderProgram_ = nullptr;
|
||||
}
|
||||
// Will usually be clear already.
|
||||
for (auto iter : postShaderModules_) {
|
||||
render_->DeleteShader(iter);
|
||||
|
@ -693,8 +537,6 @@ void FramebufferManagerGLES::DestroyAllFBOs() {
|
|||
tempFB.second.fbo->Release();
|
||||
}
|
||||
tempFBOs_.clear();
|
||||
|
||||
SetNumExtraFBOs(0);
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::Resized() {
|
||||
|
@ -706,7 +548,7 @@ void FramebufferManagerGLES::Resized() {
|
|||
}
|
||||
|
||||
// Might have a new post shader - let's compile it.
|
||||
CompilePostShader();
|
||||
presentation_->UpdatePostShader();
|
||||
|
||||
// render_->SetLineWidth(renderWidth_ / 480.0f);
|
||||
}
|
||||
|
|
|
@ -76,10 +76,7 @@ private:
|
|||
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void Bind2DShader() override;
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
void ShowPostShaderError(const std::string &errorMessage);
|
||||
void CompileDraw2DProgram();
|
||||
void CompilePostShader();
|
||||
|
||||
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
|
||||
|
@ -94,7 +91,6 @@ private:
|
|||
u8 *convBuf_ = nullptr;
|
||||
u32 convBufSize_ = 0;
|
||||
GLRProgram *draw2dprogram_ = nullptr;
|
||||
GLRProgram *postShaderProgram_ = nullptr;
|
||||
std::vector<GLRShader *> postShaderModules_;
|
||||
|
||||
GLRProgram *stencilUploadProgram_ = nullptr;
|
||||
|
|
|
@ -236,9 +236,12 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
|||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
presentation_->UpdateSize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
// TODO, also deal with RB swizzle.
|
||||
PostShaderUniforms uniforms{};
|
||||
|
||||
presentation_->UpdateSize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
||||
presentation_->SourceTexture(fbTex);
|
||||
presentation_->CopyToOutput(outputFlags, g_Config.iInternalScreenRotation, u0, v0, u1, v1);
|
||||
presentation_->CopyToOutput(outputFlags, g_Config.iInternalScreenRotation, u0, v0, u1, v1, uniforms);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput(bool reallyDirty) {
|
||||
|
|
|
@ -84,6 +84,7 @@ void main() {
|
|||
FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) :
|
||||
FramebufferManagerCommon(draw),
|
||||
vulkan_(vulkan) {
|
||||
presentation_->SetLanguage(GLSL_VULKAN);
|
||||
|
||||
DeviceRestore(vulkan, draw);
|
||||
|
||||
|
@ -158,16 +159,6 @@ void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
|||
vulkan_->Delete().QueueDeleteSampler(linearSampler_);
|
||||
if (nearestSampler_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteSampler(nearestSampler_);
|
||||
|
||||
if (postVs_) {
|
||||
vulkan2D_->PurgeVertexShader(postVs_);
|
||||
vulkan_->Delete().QueueDeleteShaderModule(postVs_);
|
||||
}
|
||||
if (postFs_) {
|
||||
vulkan2D_->PurgeFragmentShader(postFs_);
|
||||
vulkan_->Delete().QueueDeleteShaderModule(postFs_);
|
||||
}
|
||||
pipelinePostShader_ = VK_NULL_HANDLE; // actual pipeline should get destroyed by vulkan2d.
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) {
|
||||
|
@ -329,9 +320,6 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
|
|||
VkBuffer vbuffer;
|
||||
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
|
||||
renderManager->BindPipeline(cur2DPipeline_);
|
||||
if (cur2DPipeline_ == pipelinePostShader_) {
|
||||
renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT, 0, (int)sizeof(postShaderUniforms_), &postShaderUniforms_);
|
||||
}
|
||||
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
|
||||
}
|
||||
|
||||
|
@ -340,26 +328,6 @@ void FramebufferManagerVulkan::Bind2DShader() {
|
|||
cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) {
|
||||
if (!pipelinePostShader_) {
|
||||
if (usePostShader_) {
|
||||
CompilePostShader();
|
||||
}
|
||||
if (!usePostShader_) {
|
||||
SetNumExtraFBOs(0);
|
||||
Bind2DShader();
|
||||
return;
|
||||
} else {
|
||||
SetNumExtraFBOs(1);
|
||||
}
|
||||
}
|
||||
|
||||
postShaderUniforms_ = uniforms;
|
||||
cur2DPipeline_ = pipelinePostShader_;
|
||||
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
|
||||
}
|
||||
|
||||
int FramebufferManagerVulkan::GetLineWidth() {
|
||||
if (g_Config.iInternalResolution == 0) {
|
||||
return std::max(1, (int)(renderWidth_ / 480));
|
||||
|
@ -591,8 +559,6 @@ void FramebufferManagerVulkan::DestroyAllFBOs() {
|
|||
tempFB.second.fbo->Release();
|
||||
}
|
||||
tempFBOs_.clear();
|
||||
|
||||
SetNumExtraFBOs(0);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::Resized() {
|
||||
|
@ -603,89 +569,5 @@ void FramebufferManagerVulkan::Resized() {
|
|||
}
|
||||
|
||||
// Might have a new post shader - let's compile it.
|
||||
CompilePostShader();
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::CompilePostShader() {
|
||||
if (postVs_) {
|
||||
vulkan2D_->PurgeVertexShader(postVs_);
|
||||
vulkan_->Delete().QueueDeleteShaderModule(postVs_);
|
||||
}
|
||||
if (postFs_) {
|
||||
vulkan2D_->PurgeFragmentShader(postFs_);
|
||||
vulkan_->Delete().QueueDeleteShaderModule(postFs_);
|
||||
}
|
||||
|
||||
const ShaderInfo *shaderInfo = nullptr;
|
||||
if (g_Config.sPostShaderName == "Off") {
|
||||
usePostShader_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
usePostShader_ = false;
|
||||
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
std::string errorVSX, errorFSX;
|
||||
std::string vsSource;
|
||||
std::string fsSource;
|
||||
if (shaderInfo) {
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
presentation_->UpdateShaderInfo(shaderInfo);
|
||||
size_t sz;
|
||||
char *vs = (char *)VFSReadFile(shaderInfo->vertexShaderFile.c_str(), &sz);
|
||||
if (!vs)
|
||||
return;
|
||||
char *fs = (char *)VFSReadFile(shaderInfo->fragmentShaderFile.c_str(), &sz);
|
||||
if (!fs) {
|
||||
free(vs);
|
||||
return;
|
||||
}
|
||||
std::string vsSourceGLSL = vs;
|
||||
std::string fsSourceGLSL = fs;
|
||||
free(vs);
|
||||
free(fs);
|
||||
TranslatedShaderMetadata metaVS, metaFS;
|
||||
if (!TranslateShader(&vsSource, GLSL_VULKAN, &metaVS, vsSourceGLSL, GLSL_140, Draw::ShaderStage::VERTEX, &errorVSX))
|
||||
return;
|
||||
if (!TranslateShader(&fsSource, GLSL_VULKAN, &metaFS, fsSourceGLSL, GLSL_140, Draw::ShaderStage::FRAGMENT, &errorFSX))
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Delete the old pipeline?
|
||||
|
||||
std::string errorVS;
|
||||
std::string errorFS;
|
||||
postVs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, vsSource.c_str(), &errorVS);
|
||||
postFs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, fsSource.c_str(), &errorFS);
|
||||
|
||||
VkRenderPass backbufferRP = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS);
|
||||
|
||||
if (postVs_ && postFs_) {
|
||||
pipelinePostShader_ = vulkan2D_->GetPipeline(backbufferRP, postVs_, postFs_, true, Vulkan2D::VK2DDepthStencilMode::NONE);
|
||||
usePostShader_ = true;
|
||||
} else {
|
||||
ELOG("Failed to compile.");
|
||||
pipelinePostShader_ = VK_NULL_HANDLE;
|
||||
usePostShader_ = false;
|
||||
|
||||
std::string firstLine;
|
||||
std::string errorString = errorVS + "\n" + errorFS;
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < errorString.size(); i++) {
|
||||
if (errorString[i] == '\n' && i == start) {
|
||||
start = i + 1;
|
||||
} else if (errorString[i] == '\n') {
|
||||
firstLine = errorString.substr(start, i - start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!firstLine.empty()) {
|
||||
host->NotifyUserMessage("Post-shader error: " + firstLine + "...", 10.0f, 0xFF3090FF);
|
||||
} else {
|
||||
host->NotifyUserMessage("Post-shader error, see log for details", 10.0f, 0xFF3090FF);
|
||||
}
|
||||
}
|
||||
presentation_->UpdatePostShader();
|
||||
}
|
||||
|
|
|
@ -70,9 +70,7 @@ public:
|
|||
void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth);
|
||||
|
||||
protected:
|
||||
void CompilePostShader();
|
||||
void Bind2DShader() override;
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
|
||||
// Used by ReadFramebufferToMemory and later framebuffer block copies
|
||||
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
|
||||
|
@ -121,12 +119,6 @@ private:
|
|||
|
||||
VkPipeline cur2DPipeline_ = VK_NULL_HANDLE;
|
||||
|
||||
// Postprocessing
|
||||
VkShaderModule postVs_ = VK_NULL_HANDLE;
|
||||
VkShaderModule postFs_ = VK_NULL_HANDLE;
|
||||
VkPipeline pipelinePostShader_ = VK_NULL_HANDLE;
|
||||
PostShaderUniforms postShaderUniforms_;
|
||||
|
||||
VkSampler linearSampler_;
|
||||
VkSampler nearestSampler_;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue