This commit is contained in:
Henrik Rydgård committed 2022-07-11 14:00:26 +02:00
1 parent d2002eab39
commit 415ea50afa
7 files changed
+273 -23

No files matched your search

+9 -7
View File
@@ -185,10 +185,10 @@ VkShaderStageFlagBits StageToVulkan(ShaderStage stage) {
// invoke Compile again to recreate the shader then link them together.
class VKShaderModule : public ShaderModule {
public:
VKShaderModule(ShaderStage stage, const std::string &tag) : stage_(stage), tag_(tag) {
VKShaderModule(VulkanContext *vulkan, ShaderStage stage, const std::string &tag) : vulkan_(vulkan), stage_(stage), tag_(tag) {
vkstage_ = StageToVulkan(stage);
}
bool Compile(VulkanContext *vulkan, ShaderLanguage language, const uint8_t *data, size_t size);
bool Compile(ShaderLanguage language, const uint8_t *data, size_t size);
const std::string &GetSource() const { return source_; }
~VKShaderModule() {
if (module_) {
@@ -210,8 +210,7 @@ private:
std::string tag_;
};
bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, const uint8_t *data, size_t size) {
vulkan_ = vulkan;
bool VKShaderModule::Compile(ShaderLanguage language, const uint8_t *data, size_t size) {
// We'll need this to free it later.
source_ = (const char *)data;
std::vector<uint32_t> spirv;
@@ -230,7 +229,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con
}
#endif
if (vulkan->CreateShaderModule(spirv, &module_)) {
if (vulkan_->CreateShaderModule(spirv, &module_)) {
ok_ = true;
} else {
WARN_LOG(G3D, "vkCreateShaderModule failed");
@@ -1052,6 +1051,8 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
ERROR_LOG(G3D, "CreateGraphicsPipeline got passed a null shader");
return nullptr;
}
// Here we could addref the shader modules, and store them in VkPipeline for later Release -
// however, are NOT, or at least should not, be needed after creation, so not much point.
VkPipelineShaderStageCreateInfo &stage = stages[i++];
stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stage.pNext = nullptr;
@@ -1280,8 +1281,9 @@ void VKContext::BindTextures(int start, int count, Texture **textures) {
}
ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t size, const std::string &tag) {
VKShaderModule *shader = new VKShaderModule(stage, tag);
if (shader->Compile(vulkan_, language, data, size)) {
_CrtCheckMemory();
VKShaderModule *shader = new VKShaderModule(vulkan_, stage, tag);
if (shader->Compile(language, data, size)) {
return shader;
} else {
ERROR_LOG(G3D, "Failed to compile shader:\n%s", (const char *)data);
+1
View File
@@ -68,6 +68,7 @@ bool DataFormatIsDepthStencil(DataFormat fmt) {
bool RefCountedObject::Release() {
_assert_(this != nullptr);
if (refcount_ > 0 && refcount_ < 10000) {
if (--refcount_ == 0) {
delete this;
+4 -4
View File
@@ -24,13 +24,13 @@ DrawBuffer::~DrawBuffer() {
delete [] verts_;
}
void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) {
void DrawBuffer::Init(Draw::DrawContext *draw, Draw::Pipeline *pipeline) {
using namespace Draw;
if (inited_)
return;
draw_ = t3d;
draw_ = draw;
inited_ = true;
if (pipeline->RequiresBuffer()) {
@@ -40,7 +40,7 @@ void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) {
}
}
Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) {
Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *draw) {
using namespace Draw;
InputLayoutDesc desc = {
{
@@ -53,7 +53,7 @@ Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) {
},
};
return t3d->CreateInputLayout(desc);
return draw->CreateInputLayout(desc);
}
void DrawBuffer::Shutdown() {
+7 -5
View File
@@ -112,7 +112,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
shading = doFlatShading ? "flat" : "";
bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT);
bool useAdrenoBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL);
bool useDiscardStencilBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL);
bool readFramebuffer = replaceBlend == REPLACE_BLEND_COPY_FBO || colorWriteMask;
bool readFramebufferTex = readFramebuffer && !gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH);
@@ -133,7 +133,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) {
if (earlyFragmentTests) {
WRITE(p, "layout (early_fragment_tests) in;\n");
} else if (useAdrenoBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
} else if (useDiscardStencilBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n");
}
@@ -1052,9 +1052,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n");
}
WRITE(p, " gl_FragDepth = z;\n");
} else if (!earlyFragmentTests && useAdrenoBugWorkaround) {
// Adreno (and possibly MESA/others) apply early frag tests even with discard in the shader.
// Writing depth prevents the bug, even with depth_unchanged specified.
} else if (!earlyFragmentTests && useDiscardStencilBugWorkaround) {
// Older Adreno drivers and many Mali drivers apply early frag tests even with discard in the shader,
// in some situations.
// For Adreno, writing depth reliably prevents the bug, even with depth_unchanged specified.
// On Mali, results so far are mixed but this workaround works in many situations.
WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n");
}
+242 -6
View File
@@ -231,6 +231,64 @@ static const std::vector<Draw::ShaderSource> vsFlat = {
}
};
// Focused test for Mali on Vulkan.
static const std::vector<Draw::ShaderSource> fsMaliDiscard = {
{ShaderLanguage::GLSL_VULKAN,
R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout(location = 0) in vec4 oColor0;
layout(location = 1) in vec2 oTexCoord0;
layout(location = 0) out vec4 fragColor0;
layout(set = 0, binding = 1) uniform sampler2D Sampler0;
void main() {
vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
fragColor0 = color;
})"
},
};
static const std::vector<Draw::ShaderSource> fsMaliTest = {
{ShaderLanguage::GLSL_VULKAN,
R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout(location = 0) in vec4 oColor0;
layout(location = 1) in vec2 oTexCoord0;
layout(location = 0) out vec4 fragColor0;
layout(set = 0, binding = 1) uniform sampler2D Sampler0;
void main() {
fragColor0 = texture(Sampler0, oTexCoord0) * oColor0;;
})"
},
};
static const std::vector<Draw::ShaderSource> vsMaliTest = {
{ ShaderLanguage::GLSL_VULKAN,
R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (std140, set = 0, binding = 0) uniform bufferVals {
mat4 WorldViewProj;
} myBufferVals;
layout (location = 0) in vec4 pos;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec2 inTexCoord;
layout (location = 0) out vec4 outColor;
layout (location = 1) out highp vec2 outTexCoord;
out gl_PerVertex { vec4 gl_Position; };
void main() {
outColor = inColor;
outTexCoord = inTexCoord;
gl_Position = myBufferVals.WorldViewProj * pos;
})"
}
};
GPUDriverTestScreen::GPUDriverTestScreen() {
using namespace Draw;
}
@@ -280,6 +338,20 @@ GPUDriverTestScreen::~GPUDriverTestScreen() {
if (samplerNearest_)
samplerNearest_->Release();
if (chessTexture_)
chessTexture_->Release();
if (circleTexture_)
circleTexture_->Release();
for (auto pipeline : maliWriteStencilPipelines_) {
pipeline->Release();
}
for (auto pipeline : maliReadStencilPipelines_) {
pipeline->Release();
}
}
void GPUDriverTestScreen::CreateViews() {
@@ -301,20 +373,184 @@ void GPUDriverTestScreen::CreateViews() {
tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 30.0f, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, false));
anchor->Add(tabHolder_);
tabHolder_->AddTab("Discard", new LinearLayout(ORIENT_VERTICAL));
tabHolder_->AddTab("Shader", new LinearLayout(ORIENT_VERTICAL));
// TODO: Check for Vulkan
tabHolder_->AddTab("Mali Discard", new LinearLayout(ORIENT_VERTICAL));
tabHolder_->SetCurrentTab(2, true);
Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(100, WRAP_CONTENT, 10, NONE, NONE, 10));
back->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
back->OnClick.Handle<UIScreen> (this, &UIScreen::OnBack);
anchor->Add(back);
}
// In this path we're trying to get as close as possible to the situation in Surf's Up, which breaks.
void GPUDriverTestScreen::MaliDiscardTest() {
using namespace UI;
using namespace Draw;
UIContext &dc = *screenManager()->getUIContext();
DrawContext *draw = dc.GetDrawContext();
if (!chessTexture_) {
uint8_t *data = new uint8_t[32 * 32];
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 32; x++) {
data[y * 32 + x] = ((x ^ y) & 1) * 255;
}
}
TextureDesc desc{};
desc.width = 32;
desc.height = 32;
desc.depth = 1;
desc.mipLevels = 1;
desc.format = DataFormat::R8_UNORM;
desc.generateMips = false;
desc.initData.push_back(data);
chessTexture_ = draw->CreateTexture(desc);
delete[] data;
}
if (!circleTexture_) {
uint8_t *data = new uint8_t[32 * 32];
for (int y = 0; y < 32; y++) {
float dy = (y - 16.0f) / 16.0f;
for (int x = 0; x < 32; x++) {
float dx = (x - 16.0f) / 16.0f;
float alpha = std::max(0.0, 1.0 - sqrtf(dx * dx + dy * dy));
data[y * 32 + x] = (uint8_t)(alpha * 255.0);
}
}
TextureDesc desc{};
desc.width = 32;
desc.height = 32;
desc.depth = 1;
desc.mipLevels = 1;
desc.format = DataFormat::R8_UNORM;
desc.generateMips = false;
desc.initData.push_back(data);
circleTexture_ = draw->CreateTexture(desc);
delete[] data;
}
_CrtCheckMemory();
if (maliWriteStencilPipelines_.empty()) {
InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw);
ShaderModule *maliVs = CreateShader(draw, ShaderStage::Vertex, vsMaliTest);
ShaderModule *maliFsWrite = CreateShader(draw, ShaderStage::Fragment, fsMaliDiscard);
ShaderModule *maliFsRead = CreateShader(draw, ShaderStage::Fragment, fsMaliTest);
BlendStateDesc desc{};
desc.colorMask = 0xF;
desc.srcCol = BlendFactor::SRC_ALPHA;
desc.dstCol = BlendFactor::ONE_MINUS_SRC_ALPHA;
desc.srcAlpha = BlendFactor::ONE;
desc.dstAlpha = BlendFactor::ZERO;
desc.enabled = true;
BlendState *blendOn = draw->CreateBlendState(desc);
DepthStencilStateDesc writeStencil{};
writeStencil.stencilEnabled = true;
writeStencil.front.passOp = StencilOp::INCREMENT_AND_CLAMP;
writeStencil.front.failOp = StencilOp::KEEP;
writeStencil.front.depthFailOp = StencilOp::KEEP;
writeStencil.front.compareMask = 0xFF;
writeStencil.front.compareOp = Comparison::ALWAYS;
writeStencil.front.writeMask = 0x0;
writeStencil.back = writeStencil.front;
DepthStencilState *writeStencilState = draw->CreateDepthStencilState(writeStencil);
DepthStencilStateDesc readStencil{};
readStencil.stencilEnabled = true;
readStencil.front.passOp = StencilOp::KEEP;
readStencil.front.failOp = StencilOp::KEEP;
readStencil.front.depthFailOp = StencilOp::KEEP;
readStencil.front.compareMask = 0xFF;
readStencil.front.compareOp = Comparison::NOT_EQUAL;
readStencil.front.writeMask = 0x0;
readStencil.back = readStencil.front;
DepthStencilState *readStencilState = draw->CreateDepthStencilState(readStencil);
std::vector<ShaderModule *> shaders;
shaders.push_back(maliVs);
shaders.push_back(maliFsWrite);
RasterState *rasterNoCull = draw->CreateRasterState({});
Pipeline *maliWritePipeline = draw->CreateGraphicsPipeline(PipelineDesc{
Primitive::TRIANGLE_LIST,
shaders,
inputLayout,
writeStencilState,
blendOn,
rasterNoCull,
});
shaders.clear();
shaders.push_back(maliVs);
shaders.push_back(maliFsRead);
Pipeline *maliReadPipeline = draw->CreateGraphicsPipeline(PipelineDesc{
Primitive::TRIANGLE_LIST,
shaders,
inputLayout,
readStencilState,
blendOn,
rasterNoCull,
});
inputLayout->Release();
blendOn->Release();
rasterNoCull->Release();
writeStencilState->Release();
readStencilState->Release();
maliFsRead->Release();
maliFsWrite->Release();
maliVs->Release();
maliReadStencilPipelines_.push_back(maliReadPipeline);
maliWriteStencilPipelines_.push_back(maliWritePipeline);
}
_CrtCheckMemory();
for (int i = 0; i < maliReadStencilPipelines_.size(); i++) {
Bounds bounds = { 40.0f, 40.0f + (float)i * 100.0f, 96.0f, 96.0f };
dc.BeginPipeline(maliReadStencilPipelines_[i], samplerNearest_);
draw->SetStencilRef(0x0);
draw->BindTexture(0, circleTexture_);
dc.SetCurZ(0.1f);
dc.FillRect(UI::Drawable(0xFFFFFFFF), bounds);
dc.Flush();
/*
dc.BeginPipeline(maliWriteStencilPipelines_[i], samplerNearest_);
draw->SetStencilRef(0x0);
draw->BindTexture(0, chessTexture_);
dc.SetCurZ(0.1f);
dc.FillRect(UI::Drawable(0xFFFFFFFF), bounds);
dc.Flush();
*/
}
_CrtCheckMemory();
}
void GPUDriverTestScreen::DiscardTest() {
using namespace UI;
using namespace Draw;
if (!discardWriteDepthStencil_) {
DrawContext *draw = screenManager()->getDrawContext();
UIContext &dc = *screenManager()->getUIContext();
DrawContext *draw = dc.GetDrawContext();
if (!discardWriteDepthStencil_) {
// Create the special shader module.
discardFragShader_ = CreateShader(draw, ShaderStage::Fragment, fsDiscard);
@@ -447,9 +683,6 @@ void GPUDriverTestScreen::DiscardTest() {
rasterNoCull->Release();
}
UIContext &dc = *screenManager()->getUIContext();
Draw::DrawContext *draw = dc.GetDrawContext();
static const char * const writeModeNames[] = { "Stencil+Depth", "Stencil", "Depth" };
Pipeline *writePipelines[] = { discardWriteDepthStencil_, discardWriteStencil_, discardWriteDepth_ };
const int numWriteModes = ARRAY_SIZE(writeModeNames);
@@ -647,5 +880,8 @@ void GPUDriverTestScreen::render() {
case 1:
ShaderTest();
break;
case 2:
MaliDiscardTest();
break;
}
}
+9
View File
@@ -1,5 +1,7 @@
#pragma once
#include <vector>
#include "Common/System/Display.h"
#include "Common/UI/Context.h"
#include "Common/UI/View.h"
@@ -18,6 +20,7 @@ public:
void render() override;
private:
void MaliDiscardTest();
void DiscardTest();
void ShaderTest();
@@ -44,6 +47,12 @@ private:
Draw::Pipeline *drawTestDepthLessEqual_ = nullptr;
Draw::Pipeline *drawTestDepthGreater_ = nullptr;
// Mali discard pipelines
Draw::Texture *circleTexture_ = nullptr;
Draw::Texture *chessTexture_ = nullptr;
std::vector<Draw::Pipeline *> maliWriteStencilPipelines_;
std::vector<Draw::Pipeline *> maliReadStencilPipelines_;
// Shader tests
// ============
+1 -1
View File
@@ -836,7 +836,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
// Easy testing
// screenManager->push(new GPUDriverTestScreen());
screenManager->push(new GPUDriverTestScreen());
if (g_Config.bRemoteShareOnStartup && g_Config.bRemoteDebuggerOnStartup)
StartWebServer(WebServerFlags::ALL);