Merge pull request #15846 from hrydgard/minor-gpu-cleanup

Minor GPU code cleanup
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2022-08-16 13:35:16 +02:00
commit 40229becbc
22 files changed
+275 -365

No files matched your search

-17
View File
@@ -100,8 +100,6 @@ public:
}
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override;
uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) override;
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
void InvalidateCachedState() override;
@@ -1709,21 +1707,6 @@ uint64_t D3D11DrawContext::GetNativeObject(NativeObject obj, void *srcObject) {
}
}
uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
switch (channelBit) {
case FB_COLOR_BIT: return (uintptr_t)fb->colorTex;
case FB_DEPTH_BIT: return (uintptr_t)fb->depthStencilTex;
case FB_COLOR_BIT | FB_VIEW_BIT: return (uintptr_t)fb->colorRTView;
case FB_DEPTH_BIT | FB_VIEW_BIT: return (uintptr_t)fb->depthStencilRTView;
case FB_COLOR_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->colorFormat;
case FB_DEPTH_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->depthStencilFormat;
case FB_STENCIL_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->depthStencilFormat;
default:
return 0;
}
}
void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
if (fb) {
+3
View File
@@ -313,6 +313,9 @@ void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
case HLSL_D3D11:
case HLSL_D3D9:
C(" VS_OUTPUT vs_out;\n");
if (strlen(lang_.viewportYSign)) {
F(" gl_Position.y *= %s1.0;\n", lang_.viewportYSign);
}
C(" vs_out.pos = gl_Position;\n");
for (auto &varying : varyings) {
F(" vs_out.%s = %s;\n", varying.name, varying.name);
+1 -1
View File
@@ -43,7 +43,7 @@ enum FSFlags {
class ShaderWriter {
public:
ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) {
ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions = nullptr, size_t num_gl_extensions = 0) : p_(buffer), lang_(lang), stage_(stage) {
Preamble(gl_extensions, num_gl_extensions);
}
ShaderWriter(const ShaderWriter &) = delete;
-20
View File
@@ -395,8 +395,6 @@ public:
}
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override;
uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) override;
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
void SetScissorRect(int left, int top, int width, int height) override;
@@ -1580,24 +1578,6 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne
boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment);
}
uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {
if (!fbo)
return 0;
VKFramebuffer *fb = (VKFramebuffer *)fbo;
VkImageView view = VK_NULL_HANDLE;
switch (channelBit) {
case FB_COLOR_BIT:
view = fb->GetFB()->color.imageView;
break;
case FB_DEPTH_BIT:
case FB_STENCIL_BIT:
view = fb->GetFB()->depth.imageView;
break;
}
return (uintptr_t)view;
}
void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
VKFramebuffer *fb = (VKFramebuffer *)fbo;
if (fb) {
+4 -4
View File
@@ -605,12 +605,15 @@ public:
virtual void SetErrorCallback(ErrorCallbackFn callback, void *userdata) {}
// Partial pipeline state, used to create pipelines. (in practice, in d3d11 they'll use the native state objects directly).
// TODO: Possibly ditch these and just put the descs directly in PipelineDesc since only D3D11 benefits.
virtual DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) = 0;
virtual BlendState *CreateBlendState(const BlendStateDesc &desc) = 0;
virtual SamplerState *CreateSamplerState(const SamplerStateDesc &desc) = 0;
virtual RasterState *CreateRasterState(const RasterStateDesc &desc) = 0;
// virtual ComputePipeline CreateComputePipeline(const ComputePipelineDesc &desc) = 0
virtual InputLayout *CreateInputLayout(const InputLayoutDesc &desc) = 0;
virtual ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const std::string &tag = "thin3d") = 0;
virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) = 0;
// Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them.
ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return vsPresets_[preset]; }
@@ -623,9 +626,6 @@ public:
// On some hardware, you might get a 24-bit depth buffer even though you only wanted a 16-bit one.
virtual Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) = 0;
virtual ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const std::string &tag = "thin3d") = 0;
virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) = 0;
// Copies data from the CPU over into the buffer, at a specific offset. This does not change the size of the buffer and cannot write outside it.
virtual void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) = 0;
@@ -646,7 +646,7 @@ public:
// binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2).
virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) = 0;
// deprecated
// deprecated, only used by D3D9
virtual uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) {
return 0;
}
+1 -4
View File
@@ -264,7 +264,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config, c
}
void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
ShaderWriter writer(buffer, lang, ShaderStage::Fragment);
writer.DeclareSamplers(samplers);
writer.HighPrecisionFloat();
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_NONE);
@@ -289,9 +289,6 @@ void GenerateDepalVs(char *buffer, const ShaderLanguageDesc &lang) {
writer.BeginVSMain(vsInputs, Slice<UniformDef>::empty(), varyings);
writer.C(" v_texcoord = a_texcoord0;\n");
writer.C(" gl_Position = vec4(a_position, 0.0, 1.0);\n");
if (strlen(lang.viewportYSign)) {
writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign);
}
writer.EndVSMain(varyings);
}
+54 -32
View File
@@ -40,7 +40,7 @@ static const SamplerDef samplers[1] = {
};
void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
ShaderWriter writer(buffer, lang, ShaderStage::Fragment);
writer.DeclareSamplers(samplers);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_NONE);
writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n");
@@ -48,7 +48,7 @@ void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang) {
}
void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
ShaderWriter writer(buffer, lang, ShaderStage::Fragment);
writer.DeclareSamplers(samplers);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_WRITEDEPTH);
writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n");
@@ -57,35 +57,66 @@ void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) {
}
void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0);
ShaderWriter writer(buffer, lang, ShaderStage::Vertex);
writer.BeginVSMain(inputs, Slice<UniformDef>::empty(), varyings);
writer.C(" v_texcoord = a_texcoord0;\n"); // yes, this should be right. Should be 2.0 in the far corners.
writer.C(" gl_Position = vec4(a_position, 0.0, 1.0);\n");
writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign);
writer.EndVSMain(varyings);
}
// verts have positions in clip coordinates.
void FramebufferManagerCommon::Ensure2DResources() {
using namespace Draw;
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
if (!draw2DVs_) {
char *vsCode = new char[4000];
GenerateDraw2DVS(vsCode, shaderLanguageDesc);
draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs");
_assert_(draw2DVs_);
delete[] vsCode;
}
if (!draw2DSamplerLinear_) {
SamplerStateDesc descLinear{};
descLinear.magFilter = TextureFilter::LINEAR;
descLinear.minFilter = TextureFilter::LINEAR;
descLinear.mipFilter = TextureFilter::LINEAR;
descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE;
descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE;
draw2DSamplerLinear_ = draw_->CreateSamplerState(descLinear);
}
if (!draw2DSamplerNearest_) {
SamplerStateDesc descNearest{};
descNearest.magFilter = TextureFilter::NEAREST;
descNearest.minFilter = TextureFilter::NEAREST;
descNearest.mipFilter = TextureFilter::NEAREST;
descNearest.wrapU = TextureAddressMode::CLAMP_TO_EDGE;
descNearest.wrapV = TextureAddressMode::CLAMP_TO_EDGE;
draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest);
}
}
void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) {
using namespace Draw;
if (!draw2DPipelineColor_) {
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
Ensure2DResources();
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
if (!draw2DPipelineColor_) {
char *fsCode = new char[4000];
char *fsDepthCode = new char[4000];
char *vsCode = new char[4000];
GenerateDraw2DFs(fsCode, shaderLanguageDesc);
GenerateDraw2DDepthFs(fsDepthCode, shaderLanguageDesc);
GenerateDraw2DVS(vsCode, shaderLanguageDesc);
draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs");
draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs");
_assert_(draw2DFs_ && draw2DVs_);
_assert_(draw2DFs_);
if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs");
@@ -94,7 +125,8 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
draw2DFsDepth_ = nullptr;
}
InputLayoutDesc desc = {
// verts have positions in 2D clip coordinates.
static const InputLayoutDesc desc = {
{
{ 16, false },
},
@@ -139,7 +171,6 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
}
delete[] fsCode;
delete[] vsCode;
rasterNoCull->Release();
blendOff->Release();
@@ -147,29 +178,20 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
noDepthStencil->Release();
depthWriteAlways->Release();
inputLayout->Release();
SamplerStateDesc descLinear{};
descLinear.magFilter = TextureFilter::LINEAR;
descLinear.minFilter = TextureFilter::LINEAR;
descLinear.mipFilter = TextureFilter::LINEAR;
descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE;
descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE;
draw2DSamplerLinear_= draw_->CreateSamplerState(descLinear);
SamplerStateDesc descNearest{};
descLinear.magFilter = TextureFilter::NEAREST;
descLinear.minFilter = TextureFilter::NEAREST;
descLinear.mipFilter = TextureFilter::NEAREST;
descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE;
descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE;
draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest);
}
if (channel == RASTER_DEPTH && !draw2DPipelineDepth_) {
return;
switch (channel) {
case RASTER_DEPTH:
if (!draw2DPipelineDepth_) {
return;
}
draw_->BindPipeline(draw2DPipelineDepth_);
break;
case RASTER_COLOR:
draw_->BindPipeline(draw2DPipelineColor_);
break;
}
draw_->BindPipeline(channel == RASTER_COLOR ? draw2DPipelineColor_ : draw2DPipelineDepth_);
if (tex) {
draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex);
}
+2 -159
View File
@@ -114,7 +114,7 @@ void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, G
GPURecord::NotifyDisplay(framebuf, stride, format);
}
VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) {
VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) const {
addr &= 0x3FFFFFFF;
VirtualFramebuffer *match = nullptr;
for (size_t i = 0; i < vfbs_.size(); ++i) {
@@ -689,163 +689,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer
}
}
// Can't easily dynamically create these strings, we just pass along the pointer.
static const char *reinterpretStrings[3][3] = {
{
"self_reinterpret_565",
"reinterpret_565_to_5551",
"reinterpret_565_to_4444",
},
{
"reinterpret_5551_to_565",
"self_reinterpret_5551",
"reinterpret_5551_to_4444",
},
{
"reinterpret_4444_to_565",
"reinterpret_4444_to_5551",
"self_reinterpret_4444",
},
};
void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat) {
if (!useBufferedRendering_ || !vfb->fbo) {
return;
}
_assert_(newFormat != oldFormat);
// The caller is responsible for updating the format.
_assert_(newFormat == vfb->format);
ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage;
// Copy image required for now, might get rid of this later.
bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers &&
(lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx) &&
draw_->GetDeviceCaps().framebufferCopySupported;
if (!doReinterpret) {
// Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil.
if (oldFormat == GE_FORMAT_565) {
// We have to bind here instead of clear, since it can be that no framebuffer is bound.
// The backend can sometimes directly optimize it to a clear.
// Games that are marked as doing reinterpret just ignore this - better to keep the data than to clear.
// Fixes #13717.
if (!PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && !PSP_CoreParameter().compat.flags().BlueToAlpha) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret");
// Need to dirty anything that has command buffer dynamic state, in case we started a new pass above.
// Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager.
gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE);
if (currentRenderVfb_ != vfb) {
// In case ReinterpretFramebuffer was called from the texture manager.
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After FakeReinterpret");
}
}
}
return;
}
// We only reinterpret between 16 - bit formats, for now.
if (!IsGeBufferFormat16BitColor(oldFormat) || !IsGeBufferFormat16BitColor(newFormat)) {
// 16->32 and 32->16 will require some more specialized shaders.
return;
}
char *vsCode = nullptr;
char *fsCode = nullptr;
if (!reinterpretVS_) {
vsCode = new char[4000];
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
GenerateReinterpretVertexShader(vsCode, shaderLanguageDesc);
reinterpretVS_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "reinterpret_vs");
_assert_(reinterpretVS_);
}
if (!reinterpretSampler_) {
Draw::SamplerStateDesc samplerDesc{};
samplerDesc.magFilter = Draw::TextureFilter::LINEAR;
samplerDesc.minFilter = Draw::TextureFilter::LINEAR;
reinterpretSampler_ = draw_->CreateSamplerState(samplerDesc);
}
if (!reinterpretVBuf_) {
reinterpretVBuf_ = draw_->CreateBuffer(12 * 3, Draw::BufferUsageFlag::DYNAMIC | Draw::BufferUsageFlag::VERTEXDATA);
}
// See if we need to create a new pipeline.
Draw::Pipeline *pipeline = reinterpretFromTo_[(int)oldFormat][(int)newFormat];
if (!pipeline) {
fsCode = new char[4000];
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
GenerateReinterpretFragmentShader(fsCode, oldFormat, newFormat, shaderLanguageDesc);
Draw::ShaderModule *reinterpretFS = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "reinterpret_fs");
_assert_(reinterpretFS);
std::vector<Draw::ShaderModule *> shaders;
shaders.push_back(reinterpretVS_);
shaders.push_back(reinterpretFS);
using namespace Draw;
Draw::PipelineDesc desc{};
// We use a "fullscreen triangle".
// TODO: clear the stencil buffer. Hard to actually initialize it with the new alpha, though possible - let's see if
// we need it.
DepthStencilState *depth = draw_->CreateDepthStencilState({ false, false, Comparison::LESS });
BlendState *blendstateOff = draw_->CreateBlendState({ false, 0xF });
RasterState *rasterNoCull = draw_->CreateRasterState({});
// No uniforms for these, only a single texture input.
PipelineDesc pipelineDesc{ Primitive::TRIANGLE_LIST, shaders, nullptr, depth, blendstateOff, rasterNoCull, nullptr };
pipeline = draw_->CreateGraphicsPipeline(pipelineDesc);
_assert_(pipeline != nullptr);
reinterpretFromTo_[(int)oldFormat][(int)newFormat] = pipeline;
depth->Release();
blendstateOff->Release();
rasterNoCull->Release();
reinterpretFS->Release();
}
// Copy to a temp framebuffer.
Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight);
// Ideally on Vulkan this should be using the original framebuffer as an input attachment, allowing it to read from
// itself while writing.
draw_->InvalidateCachedState();
draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep");
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, reinterpretStrings[(int)oldFormat][(int)newFormat]);
draw_->BindPipeline(pipeline);
draw_->BindFramebufferAsTexture(temp, 0, Draw::FBChannel::FB_COLOR_BIT, 0);
draw_->BindSamplerStates(0, 1, &reinterpretSampler_);
draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight);
Draw::Viewport vp = Draw::Viewport{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f };
draw_->SetViewports(1, &vp);
// Vertex buffer not used - vertices generated in shader.
// TODO: Switch to a vertex buffer for GLES2/D3D9 compat.
draw_->BindVertexBuffers(0, 1, &reinterpretVBuf_, nullptr);
draw_->Draw(3, 0);
draw_->InvalidateCachedState();
// Unbind.
draw_->BindTexture(0, nullptr);
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
if (currentRenderVfb_ != vfb) {
// In case ReinterpretFramebuffer was called from the texture manager.
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After reinterpret");
}
delete[] vsCode;
delete[] fsCode;
}
void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) {
if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) {
ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height);
@@ -2480,7 +2323,7 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) {
}
}
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() const {
std::vector<FramebufferInfo> list;
for (size_t i = 0; i < vfbs_.size(); ++i) {
+11 -10
View File
@@ -249,7 +249,7 @@ public:
}
}
void RebindFramebuffer(const char *tag);
std::vector<FramebufferInfo> GetFramebufferList();
std::vector<FramebufferInfo> GetFramebufferList() const;
void CopyDisplayToOutput(bool reallyDirty);
@@ -276,25 +276,25 @@ public:
size_t NumVFBs() const { return vfbs_.size(); }
u32 PrevDisplayFramebufAddr() {
u32 PrevDisplayFramebufAddr() const {
return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0;
}
u32 DisplayFramebufAddr() {
u32 DisplayFramebufAddr() const {
return displayFramebuf_ ? displayFramebuf_->fb_address : 0;
}
u32 DisplayFramebufStride() {
u32 DisplayFramebufStride() const {
return displayFramebuf_ ? displayStride_ : 0;
}
GEBufferFormat DisplayFramebufFormat() {
GEBufferFormat DisplayFramebufFormat() const {
return displayFramebuf_ ? displayFormat_ : GE_FORMAT_INVALID;
}
bool UseBufferedRendering() {
bool UseBufferedRendering() const {
return useBufferedRendering_;
}
bool MayIntersectFramebuffer(u32 start) {
bool MayIntersectFramebuffer(u32 start) const {
// Clear the cache/kernel bits.
start = start & 0x3FFFFFFF;
// Most games only have two framebuffers at the start.
@@ -308,8 +308,8 @@ public:
return currentRenderVfb_;
}
// TODO: Break out into some form of FBO manager
VirtualFramebuffer *GetVFBAt(u32 addr);
VirtualFramebuffer *GetDisplayVFB() {
VirtualFramebuffer *GetVFBAt(u32 addr) const;
VirtualFramebuffer *GetDisplayVFB() const {
return GetVFBAt(displayFramebufPtr_);
}
@@ -349,7 +349,7 @@ public:
virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);
virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer);
const std::vector<VirtualFramebuffer *> &Framebuffers() {
const std::vector<VirtualFramebuffer *> &Framebuffers() const {
return vfbs_;
}
void ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat);
@@ -361,6 +361,7 @@ protected:
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);
void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel);
void Ensure2DResources();
bool UpdateSize();
+167 -15
View File
@@ -4,7 +4,10 @@
#include "Common/GPU/ShaderWriter.h"
#include "Common/Log.h"
#include "Common/GPU/thin3d.h"
#include "Core/System.h"
#include "GPU/Common/ReinterpretFramebuffer.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
static const VaryingDef varyings[1] = {
{ "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" },
@@ -17,12 +20,10 @@ static const SamplerDef samplers[1] = {
// TODO: We could possibly have an option to preserve any extra color precision? But gonna start without it.
// Requires full size integer math. It would be possible to make a floating point-only version with lots of
// modulo and stuff, might do it one day.
bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) {
if (!lang.bitwiseOps) {
return false;
}
void GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) {
_assert_(lang.bitwiseOps);
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
ShaderWriter writer(buffer, lang, ShaderStage::Fragment);
writer.HighPrecisionFloat();
@@ -69,24 +70,175 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff
}
writer.EndFSMain("outColor", FSFLAG_NONE);
return true;
}
bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang) {
if (!lang.bitwiseOps) {
return false;
}
ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0);
void GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang) {
_assert_(lang.bitwiseOps);
ShaderWriter writer(buffer, lang, ShaderStage::Vertex);
writer.BeginVSMain(Slice<InputDef>::empty(), Slice<UniformDef>::empty(), varyings);
writer.C(" float x = -1.0 + float((gl_VertexIndex & 1) << 2);\n");
writer.C(" float y = -1.0 + float((gl_VertexIndex & 2) << 1);\n");
writer.C(" v_texcoord = (vec2(x, y) + vec2(1.0, 1.0)) * 0.5;\n");
if (strlen(lang.viewportYSign)) {
writer.F(" y *= %s1.0;\n", lang.viewportYSign);
}
writer.C(" gl_Position = vec4(x, y, 0.0, 1.0);\n");
writer.EndVSMain(varyings);
return true;
}
// Can't easily dynamically create these strings, we just pass along the pointer.
static const char *reinterpretStrings[3][3] = {
{
"self_reinterpret_565",
"reinterpret_565_to_5551",
"reinterpret_565_to_4444",
},
{
"reinterpret_5551_to_565",
"self_reinterpret_5551",
"reinterpret_5551_to_4444",
},
{
"reinterpret_4444_to_565",
"reinterpret_4444_to_5551",
"self_reinterpret_4444",
},
};
void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat) {
if (!useBufferedRendering_ || !vfb->fbo) {
return;
}
_assert_(newFormat != oldFormat);
// The caller is responsible for updating the format.
_assert_(newFormat == vfb->format);
ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage;
// Copy image required for now, might get rid of this later.
bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers &&
(lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx) &&
draw_->GetDeviceCaps().framebufferCopySupported;
if (!doReinterpret) {
// Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil.
if (oldFormat == GE_FORMAT_565) {
// We have to bind here instead of clear, since it can be that no framebuffer is bound.
// The backend can sometimes directly optimize it to a clear.
// Games that are marked as doing reinterpret just ignore this - better to keep the data than to clear.
// Fixes #13717.
if (!PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && !PSP_CoreParameter().compat.flags().BlueToAlpha) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret");
// Need to dirty anything that has command buffer dynamic state, in case we started a new pass above.
// Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager.
gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE);
if (currentRenderVfb_ != vfb) {
// In case ReinterpretFramebuffer was called from the texture manager.
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After FakeReinterpret");
}
}
}
return;
}
// We only reinterpret between 16 - bit formats, for now.
if (!IsGeBufferFormat16BitColor(oldFormat) || !IsGeBufferFormat16BitColor(newFormat)) {
// 16->32 and 32->16 will require some more specialized shaders.
return;
}
char *vsCode = nullptr;
char *fsCode = nullptr;
if (!reinterpretVS_) {
vsCode = new char[4000];
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
GenerateReinterpretVertexShader(vsCode, shaderLanguageDesc);
reinterpretVS_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "reinterpret_vs");
_assert_(reinterpretVS_);
}
if (!reinterpretSampler_) {
Draw::SamplerStateDesc samplerDesc{};
samplerDesc.magFilter = Draw::TextureFilter::LINEAR;
samplerDesc.minFilter = Draw::TextureFilter::LINEAR;
reinterpretSampler_ = draw_->CreateSamplerState(samplerDesc);
}
if (!reinterpretVBuf_) {
reinterpretVBuf_ = draw_->CreateBuffer(12 * 3, Draw::BufferUsageFlag::DYNAMIC | Draw::BufferUsageFlag::VERTEXDATA);
}
// See if we need to create a new pipeline.
Draw::Pipeline *pipeline = reinterpretFromTo_[(int)oldFormat][(int)newFormat];
if (!pipeline) {
fsCode = new char[4000];
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
GenerateReinterpretFragmentShader(fsCode, oldFormat, newFormat, shaderLanguageDesc);
Draw::ShaderModule *reinterpretFS = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "reinterpret_fs");
_assert_(reinterpretFS);
std::vector<Draw::ShaderModule *> shaders;
shaders.push_back(reinterpretVS_);
shaders.push_back(reinterpretFS);
using namespace Draw;
Draw::PipelineDesc desc{};
// We use a "fullscreen triangle".
// TODO: clear the stencil buffer. Hard to actually initialize it with the new alpha, though possible - let's see if
// we need it.
DepthStencilState *depth = draw_->CreateDepthStencilState({ false, false, Comparison::LESS });
BlendState *blendstateOff = draw_->CreateBlendState({ false, 0xF });
RasterState *rasterNoCull = draw_->CreateRasterState({});
// No uniforms for these, only a single texture input.
PipelineDesc pipelineDesc{ Primitive::TRIANGLE_LIST, shaders, nullptr, depth, blendstateOff, rasterNoCull, nullptr };
pipeline = draw_->CreateGraphicsPipeline(pipelineDesc);
_assert_(pipeline != nullptr);
reinterpretFromTo_[(int)oldFormat][(int)newFormat] = pipeline;
depth->Release();
blendstateOff->Release();
rasterNoCull->Release();
reinterpretFS->Release();
}
// Copy to a temp framebuffer.
Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight);
// Ideally on Vulkan this should be using the original framebuffer as an input attachment, allowing it to read from
// itself while writing.
draw_->InvalidateCachedState();
draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep");
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, reinterpretStrings[(int)oldFormat][(int)newFormat]);
draw_->BindPipeline(pipeline);
draw_->BindFramebufferAsTexture(temp, 0, Draw::FBChannel::FB_COLOR_BIT, 0);
draw_->BindSamplerStates(0, 1, &reinterpretSampler_);
draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight);
Draw::Viewport vp = Draw::Viewport{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f };
draw_->SetViewports(1, &vp);
// Vertex buffer not used - vertices generated in shader.
// TODO: Switch to a vertex buffer for GLES2/D3D9 compat.
draw_->BindVertexBuffers(0, 1, &reinterpretVBuf_, nullptr);
draw_->Draw(3, 0);
draw_->InvalidateCachedState();
// Unbind.
draw_->BindTexture(0, nullptr);
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
if (currentRenderVfb_ != vfb) {
// In case ReinterpretFramebuffer was called from the texture manager.
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After reinterpret");
}
delete[] vsCode;
delete[] fsCode;
}
+2 -2
View File
@@ -4,8 +4,8 @@
#include "GPU/GPUCommon.h"
#include "Common/GPU/ShaderWriter.h"
bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang);
void GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang);
// Just a single one. Can probably be shared with a lot of similar use cases.
// Generates the coordinates for a fullscreen triangle.
bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang);
void GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang);
-1
View File
@@ -123,7 +123,6 @@ void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) {
writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners.
}
writer.C(" gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);\n");
writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign);
writer.EndVSMain(varyings);
}
-60
View File
@@ -20,74 +20,14 @@
#include <D3Dcompiler.h>
#include "Common/Common.h"
#include "Common/Data/Convert/ColorConv.h"
#include "Common/GPU/thin3d.h"
#include "Core/MemMap.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Debugger/Stepping.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/PresentationCommon.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/D3D11/FramebufferManagerD3D11.h"
#include "GPU/D3D11/ShaderManagerD3D11.h"
#include "GPU/D3D11/TextureCacheD3D11.h"
#include "GPU/D3D11/DrawEngineD3D11.h"
#ifdef _M_SSE
#include <emmintrin.h>
#endif
FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
: FramebufferManagerCommon(draw) {
device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
featureLevel_ = (D3D_FEATURE_LEVEL)draw->GetNativeObject(Draw::NativeObject::FEATURE_LEVEL);
presentation_->SetLanguage(HLSL_D3D11);
preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM;
}
static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
size_t x = 0;
#ifdef _M_SSE
size_t sseSize = (c / 4) * 4;
const __m128i srcMask = _mm_set1_epi32(0x00FFFFFF);
const __m128i dstMask = _mm_set1_epi32(0xFF000000);
__m128i *dst = (__m128i *)dstp;
const __m128i *src = (const __m128i *)srcp;
for (; x < sseSize; x += 4) {
const __m128i bits24 = _mm_and_si128(_mm_load_si128(src), srcMask);
const __m128i bits8 = _mm_and_si128(_mm_load_si128(dst), dstMask);
_mm_store_si128(dst, _mm_or_si128(bits24, bits8));
dst++;
src++;
}
#endif
// Copy the remaining pixels that didn't fit in SSE.
for (; x < c; ++x) {
memcpy(dstp + x, srcp + x, 3);
}
}
// Nobody calls this yet.
void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0");
return;
}
const u32 z_address = vfb->z_address;
// TODO
}
void FramebufferManagerD3D11::EndFrame() {
}
-9
View File
@@ -34,13 +34,4 @@ class ShaderManagerD3D11;
class FramebufferManagerD3D11 : public FramebufferManagerCommon {
public:
FramebufferManagerD3D11(Draw::DrawContext *draw);
void EndFrame();
private:
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
ID3D11Device *device_;
ID3D11DeviceContext *context_;
D3D_FEATURE_LEVEL featureLevel_;
};
-3
View File
@@ -232,7 +232,6 @@ void GPU_D3D11::BeginFrame() {
textureCacheD3D11_->StartFrame();
drawEngine_.BeginFrame();
// fragmentTestCache_.Decimate();
shaderManagerD3D11_->DirtyLastShader();
@@ -255,9 +254,7 @@ void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) {
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF);
framebufferManagerD3D11_->CopyDisplayToOutput(reallyDirty);
framebufferManagerD3D11_->EndFrame();
// shaderManager_->EndFrame();
shaderManagerD3D11_->DirtyLastShader();
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
-1
View File
@@ -280,7 +280,6 @@ void GPU_DX9::ReapplyGfxState() {
void GPU_DX9::BeginFrame() {
textureCacheDX9_->StartFrame();
drawEngine_.BeginFrame();
// fragmentTestCache_.Decimate();
GPUCommon::BeginFrame();
shaderManagerDX9_->DirtyShader();
-1
View File
@@ -36,7 +36,6 @@
#include "GPU/Debugger/Stepping.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
#include "GPU/GLES/TextureCacheGLES.h"
#include "GPU/GLES/DrawEngineGLES.h"
#include "GPU/GLES/ShaderManagerGLES.h"
FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) :
-2
View File
@@ -61,6 +61,4 @@ private:
int u_depthDownloadFactor = -1;
int u_depthDownloadShift = -1;
int u_depthDownloadTo8 = -1;
DrawEngineGLES *drawEngineGL_ = nullptr;
};
+1 -1
View File
@@ -2969,7 +2969,7 @@ bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false;
}
std::vector<FramebufferInfo> GPUCommon::GetFramebufferList() {
std::vector<FramebufferInfo> GPUCommon::GetFramebufferList() const {
return framebufferManager_->GetFramebufferList();
}
+2 -2
View File
@@ -230,11 +230,11 @@ public:
const std::list<int>& GetDisplayLists() override {
return dlQueue;
}
std::vector<FramebufferInfo> GetFramebufferList() override;
std::vector<FramebufferInfo> GetFramebufferList() const override;
void ClearShaderCache() override {}
void CleanupBeforeUI() override {}
s64 GetListTicks(int listid) override {
s64 GetListTicks(int listid) const override {
if (listid >= 0 && listid < DisplayListMaxCount) {
return dls[listid].waitTicks;
}
+2 -2
View File
@@ -253,8 +253,8 @@ public:
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) = 0;
virtual const std::list<int>& GetDisplayLists() = 0;
// TODO: Currently Qt only, needs to be cleaned up.
virtual std::vector<FramebufferInfo> GetFramebufferList() = 0;
virtual s64 GetListTicks(int listid) = 0;
virtual std::vector<FramebufferInfo> GetFramebufferList() const = 0;
virtual s64 GetListTicks(int listid) const = 0;
// For debugging. The IDs returned are opaque, do not poke in them or display them in any way.
virtual std::vector<std::string> DebugGetShaderIDs(DebugShaderType type) = 0;
+25 -19
View File
@@ -181,19 +181,23 @@ bool TestReinterpretShaders() {
bool failed = false;
for (int k = 0; k < ARRAY_SIZE(languages); k++) {
printf("=== %s ===\n\n", ShaderLanguageToString(languages[k]));
ShaderLanguageDesc desc(languages[k]);
if (!GenerateReinterpretVertexShader(buffer, desc)) {
printf("Failed!\n%s\n", buffer);
// These require bitwise operations.
if (!desc.bitwiseOps) {
continue;
}
GenerateReinterpretVertexShader(buffer, desc);
std::string errorMessage;
if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) {
printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
return false;
} else {
std::string errorMessage;
if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) {
printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
return false;
} else {
//printf("===\n%s\n===\n", buffer);
}
//printf("===\n%s\n===\n", buffer);
}
}
@@ -201,23 +205,25 @@ bool TestReinterpretShaders() {
printf("=== %s ===\n\n", ShaderLanguageToString(languages[k]));
ShaderLanguageDesc desc(languages[k]);
// These require bitwise operations.
if (!desc.bitwiseOps) {
continue;
}
std::string errorMessage;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == j)
continue; // useless shader!
if (!GenerateReinterpretFragmentShader(buffer, fmts[i], fmts[j], desc)) {
printf("Failed!\n%s\n", buffer);
GenerateReinterpretFragmentShader(buffer, fmts[i], fmts[j], desc);
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
return false;
} else {
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
return false;
} else {
printf("===\n%s\n===\n", buffer);
}
printf("===\n%s\n===\n", buffer);
}
}
}