mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
wip
This commit is contained in:
1 parent
d2002eab39
commit
415ea50afa
7 files changed
+273
-23
No files matched your search
@@ -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);
|
||||
|
||||
@@ -68,6 +68,7 @@ bool DataFormatIsDepthStencil(DataFormat fmt) {
|
||||
|
||||
|
||||
bool RefCountedObject::Release() {
|
||||
_assert_(this != nullptr);
|
||||
if (refcount_ > 0 && refcount_ < 10000) {
|
||||
if (--refcount_ == 0) {
|
||||
delete this;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user