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:
Unknown W. Brackets 2020-05-10 16:53:15 -07:00
parent d17c5b30e1
commit cb94487a16
13 changed files with 372 additions and 611 deletions

View file

@ -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() {

View file

@ -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 {

View file

@ -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);

View file

@ -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_;
};

View file

@ -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();
}

View file

@ -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];
};

View file

@ -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) {

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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();
}

View file

@ -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_;