From cb94487a166bb72e46fd05e0baf26157a53a40f7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 10 May 2020 16:53:15 -0700 Subject: [PATCH] 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. --- GPU/Common/FramebufferCommon.cpp | 170 ++++---------- GPU/Common/FramebufferCommon.h | 7 - GPU/Common/PresentationCommon.cpp | 320 ++++++++++++++++++++++---- GPU/Common/PresentationCommon.h | 40 +++- GPU/D3D11/FramebufferManagerD3D11.cpp | 123 +--------- GPU/D3D11/FramebufferManagerD3D11.h | 6 - GPU/Directx9/FramebufferDX9.cpp | 13 +- GPU/Directx9/FramebufferDX9.h | 1 - GPU/GLES/FramebufferManagerGLES.cpp | 162 +------------ GPU/GLES/FramebufferManagerGLES.h | 4 - GPU/Software/SoftGpu.cpp | 7 +- GPU/Vulkan/FramebufferVulkan.cpp | 122 +--------- GPU/Vulkan/FramebufferVulkan.h | 8 - 13 files changed, 372 insertions(+), 611 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 6d7c127e25..1a3fab51ea 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -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() { diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 4eb53ab7d8..b2e132cb7d 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -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 extraFBOs_; - bool needGLESRebinds_ = false; struct TempFBOInfo { diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index c78bd73d94..2c95888edf 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -17,15 +17,20 @@ #include #include +#include #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 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 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 @@ -223,6 +338,13 @@ static void DoRelease(T *&obj) { obj = nullptr; } +template +static void DoReleaseVector(std::vector &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); diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 4584954d61..db5c3003d9 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -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 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 postShaderModules_; + std::vector postShaderPipelines_; + std::vector 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_; }; diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index e299eef751..27fe422d08 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -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 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(); } diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 33f9bdbf36..d1c0e2440a 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -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]; }; diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index f8fa9dada8..579c00f42b 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -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) { diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index aecd1e4e9b..b84e548f0d 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -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 diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 6039a47b16..5b331b8b9a 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -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 shaders; - shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vshader, "postshader")); - shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fshader, "postshader")); - std::vector 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 inits; - inits.push_back({ &u_postShaderTex, 0, 0 }); - std::vector 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 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); } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 52de5fac32..22e2f25445 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -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 postShaderModules_; GLRProgram *stencilUploadProgram_ = nullptr; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index e34584a1d0..e5f35b155b 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -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) { diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index e3146ee808..6fbd57214b 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -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(); } diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index e159fcbde4..be5a08b8c5 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -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_;