mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #21829 from hrydgard/more-graphics-fixes
ImGeDebugger fix, texture cache crashfix
This commit is contained in:
@@ -303,7 +303,8 @@ public:
|
||||
// return value and skip the draw if we're in a bad state. In that case, call ReportBadState.
|
||||
// The old assert wasn't very helpful in figuring out what caused it anyway...
|
||||
bool BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VKRPipelineLayout *pipelineLayout) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && pipeline != nullptr);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
if (!curRenderStep_ || curRenderStep_->stepType != VKRStepType::RENDER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -474,6 +474,7 @@ public:
|
||||
|
||||
void BindPipeline(Pipeline *pipeline) override {
|
||||
curPipeline_ = (VKPipeline *)pipeline;
|
||||
_dbg_assert_(curPipeline_->pipeline);
|
||||
}
|
||||
|
||||
void BindVertexBuffer(Buffer *vertexBuffer, int offset) override {
|
||||
@@ -1246,8 +1247,10 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
vkshader->AddRef();
|
||||
pipeline->deps.push_back(vkshader);
|
||||
if (vkshader->GetStage() == ShaderStage::Vertex) {
|
||||
_dbg_assert_(!gDesc.vertexShader); // can't have two
|
||||
gDesc.vertexShader = vkshader->Get();
|
||||
} else if (vkshader->GetStage() == ShaderStage::Fragment) {
|
||||
_dbg_assert_(!gDesc.fragmentShader); // can't have two
|
||||
gDesc.fragmentShader = vkshader->Get();
|
||||
} else {
|
||||
ERROR_LOG(Log::G3D, "Bad stage");
|
||||
@@ -1301,6 +1304,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
}
|
||||
|
||||
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d");
|
||||
_dbg_assert_(pipeline->pipeline);
|
||||
|
||||
if (desc.uniformDesc) {
|
||||
pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize;
|
||||
|
||||
+28
-14
@@ -210,11 +210,14 @@ const UniformDef g_uniforms[] = {
|
||||
{ "vec2", "TintSaturation", 1 },
|
||||
};
|
||||
|
||||
static ShaderModule *GenerateVShader(DrawContext *draw, bool texCoords, bool tint) {
|
||||
static ShaderModule *GenerateVShader(DrawContext *draw, VertexShaderPreset preset, bool tintSupported) {
|
||||
const ShaderLanguageDesc &shaderLanguageDesc = draw->GetShaderLanguageDesc();
|
||||
char code[2048];
|
||||
ShaderWriter vsWriter(code, shaderLanguageDesc, ShaderStage::Vertex);
|
||||
|
||||
const bool texCoords = preset != VS_COLOR_2D;
|
||||
const bool tint = tintSupported && (preset == VS_TEXTURE_COLOR_2D || preset == VS_COLOR_2D);
|
||||
|
||||
if (tint) {
|
||||
vsWriter.C(R"(
|
||||
vec3 rgb2hsv(vec3 c) {
|
||||
@@ -252,10 +255,14 @@ vec3 hsv2rgb(vec3 c) {
|
||||
return draw->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)code, strlen(code));
|
||||
}
|
||||
|
||||
static ShaderModule *GenerateFShader(DrawContext *draw, bool texturing, bool rbSwizzle) {
|
||||
static ShaderModule *GenerateFShader(DrawContext *draw, FragmentShaderPreset preset) {
|
||||
const ShaderLanguageDesc &shaderLanguageDesc = draw->GetShaderLanguageDesc();
|
||||
char code[2048];
|
||||
ShaderWriter fsWriter(code, shaderLanguageDesc, ShaderStage::Fragment);
|
||||
|
||||
const bool texturing = preset != FS_COLOR_2D;
|
||||
const bool rbSwizzle = preset == FS_TEXTURE_COLOR_2D_RB_SWIZZLE;
|
||||
|
||||
fsWriter.DeclareSamplers(g_samplers);
|
||||
fsWriter.BeginFSMain(g_uniforms, texturing ? Slice(g_varyingsTex) : Slice(g_varyings));
|
||||
if (texturing) {
|
||||
@@ -266,6 +273,9 @@ static ShaderModule *GenerateFShader(DrawContext *draw, bool texturing, bool rbS
|
||||
} else {
|
||||
fsWriter.C(" * oColor0;\n");
|
||||
}
|
||||
if (preset == FS_TEXTURE_COLOR_2D_ALPHA_TO_GRAY) {
|
||||
fsWriter.C("col.rgb = splat3(col.a);\n");
|
||||
}
|
||||
} else {
|
||||
fsWriter.C("vec4 col = oColor0;\n");
|
||||
}
|
||||
@@ -275,19 +285,23 @@ static ShaderModule *GenerateFShader(DrawContext *draw, bool texturing, bool rbS
|
||||
}
|
||||
|
||||
bool DrawContext::CreatePresets() {
|
||||
bool tintSupported = true;
|
||||
if (bugs_.Has(Bugs::RASPBERRY_SHADER_COMP_HANG)) {
|
||||
tintSupported = false;
|
||||
bool tintSupported = !bugs_.Has(Bugs::RASPBERRY_SHADER_COMP_HANG);
|
||||
|
||||
for (int i = 0; i < VS_MAX_PRESET; i++) {
|
||||
vsPresets_[i] = GenerateVShader(this, (VertexShaderPreset)i, tintSupported);
|
||||
if (!vsPresets_[i]) {
|
||||
WARN_LOG(Log::G3D, "Failed to create vertex shader preset %d", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vsPresets_[VS_TEXTURE_COLOR_2D] = GenerateVShader(this, true, tintSupported);
|
||||
vsPresets_[VS_COLOR_2D] = GenerateVShader(this, false, tintSupported);
|
||||
|
||||
fsPresets_[FS_TEXTURE_COLOR_2D] = GenerateFShader(this, true, false);
|
||||
fsPresets_[FS_COLOR_2D] = GenerateFShader(this, false, false);
|
||||
fsPresets_[FS_TEXTURE_COLOR_2D_RB_SWIZZLE] = GenerateFShader(this, true, true);
|
||||
|
||||
return vsPresets_[VS_TEXTURE_COLOR_2D] && vsPresets_[VS_COLOR_2D] && fsPresets_[FS_TEXTURE_COLOR_2D] && fsPresets_[FS_COLOR_2D] && fsPresets_[FS_TEXTURE_COLOR_2D_RB_SWIZZLE];
|
||||
for (int i = 0; i < FS_MAX_PRESET; i++) {
|
||||
fsPresets_[i] = GenerateFShader(this, (FragmentShaderPreset)i);
|
||||
if (!fsPresets_[i]) {
|
||||
WARN_LOG(Log::G3D, "Failed to create fragment shader preset %d", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawContext::DestroyPresets() {
|
||||
|
||||
+16
-6
@@ -148,6 +148,7 @@ enum class Primitive {
|
||||
enum VertexShaderPreset : int {
|
||||
VS_COLOR_2D,
|
||||
VS_TEXTURE_COLOR_2D,
|
||||
VS_TEXTURE_COLOR_2D_NO_TINT,
|
||||
VS_MAX_PRESET,
|
||||
};
|
||||
|
||||
@@ -155,6 +156,7 @@ enum FragmentShaderPreset : int {
|
||||
FS_COLOR_2D,
|
||||
FS_TEXTURE_COLOR_2D,
|
||||
FS_TEXTURE_COLOR_2D_RB_SWIZZLE,
|
||||
FS_TEXTURE_COLOR_2D_ALPHA_TO_GRAY,
|
||||
FS_MAX_PRESET,
|
||||
};
|
||||
|
||||
@@ -770,8 +772,16 @@ public:
|
||||
virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) = 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]; }
|
||||
ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return fsPresets_[preset]; }
|
||||
ShaderModule *GetVshaderPreset(VertexShaderPreset preset) {
|
||||
ShaderModule *module = vsPresets_[preset];
|
||||
_dbg_assert_(module->GetStage() == ShaderStage::Vertex);
|
||||
return module;
|
||||
}
|
||||
ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) {
|
||||
ShaderModule *module = fsPresets_[preset];
|
||||
_dbg_assert_(module->GetStage() == ShaderStage::Fragment);
|
||||
return module;
|
||||
}
|
||||
|
||||
// Resources
|
||||
virtual Buffer *CreateBuffer(size_t size, uint32_t usageFlags) = 0;
|
||||
@@ -911,13 +921,13 @@ public:
|
||||
protected:
|
||||
HistoryBuffer<FrameTimeData, FRAME_TIME_HISTORY_LENGTH> frameTimeHistory_;
|
||||
|
||||
ShaderModule *vsPresets_[VS_MAX_PRESET];
|
||||
ShaderModule *fsPresets_[FS_MAX_PRESET];
|
||||
ShaderModule *vsPresets_[VS_MAX_PRESET]{};
|
||||
ShaderModule *fsPresets_[FS_MAX_PRESET]{};
|
||||
|
||||
ShaderLanguageDesc shaderLanguageDesc_;
|
||||
|
||||
int targetWidth_;
|
||||
int targetHeight_;
|
||||
int targetWidth_ = 0;
|
||||
int targetHeight_ = 0;
|
||||
|
||||
Bugs bugs_;
|
||||
};
|
||||
|
||||
@@ -543,12 +543,6 @@ bool DrawEngineCommon::TestBoundingBoxFast(const float *cullMatrix, const void *
|
||||
// 2D bounding box test against scissor. No indexing yet.
|
||||
// Only supports non-indexed draws with float positions. TODO: Add more float formats.
|
||||
bool DrawEngineCommon::TestBoundingBoxThrough(GEPrimitiveType prim, const void *vdata, const void *idata, int vertexCount, const VertexDecoder *dec, u32 vertType, int *bytesRead, ClipInfoFlags *flags) {
|
||||
// Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR.
|
||||
// Let's always say objects are within bounds.
|
||||
if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For through mode, we only check FlatZ.
|
||||
*flags |= ClipInfoFlags::Valid;
|
||||
|
||||
@@ -628,6 +622,13 @@ bool DrawEngineCommon::TestBoundingBoxThrough(GEPrimitiveType prim, const void *
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR.
|
||||
// Let's always say objects are within bounds.
|
||||
if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (allOutsideLeft || allOutsideTop || allOutsideRight || allOutsideBottom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1095,14 +1095,14 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
truncate_cpy(replacedAlpha, "1.0");
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
case STENCIL_VALUE_INCR_4BIT:
|
||||
case STENCIL_VALUE_DECR_4BIT:
|
||||
// We're adding/subtracting, just by the smallest value in 4-bit.
|
||||
snprintf(replacedAlpha, sizeof(replacedAlpha), "%f", 1.0 / 15.0);
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
case STENCIL_VALUE_INCR_8BIT:
|
||||
case STENCIL_VALUE_DECR_8BIT:
|
||||
// We're adding/subtracting, just by the smallest value in 8-bit.
|
||||
snprintf(replacedAlpha, sizeof(replacedAlpha), "%f", 1.0 / 255.0);
|
||||
break;
|
||||
@@ -1204,12 +1204,12 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
if (writeDepth) {
|
||||
if (gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
if (fsDepthClamp) {
|
||||
WRITE(p, " gl_FragDepth = clamp(floor(projZ), 0.0, 65536.0) / 65536.0;\n");
|
||||
WRITE(p, " gl_FragDepth = clamp(floor(projZ), 0.0, 65535.0) / 65535.0;\n");
|
||||
} else {
|
||||
WRITE(p, " gl_FragDepth = floor(gl_FragCoord.z) / 65536.0;\n");
|
||||
WRITE(p, " gl_FragDepth = floor(gl_FragCoord.z * 65535.0) / 65535.0;\n");
|
||||
}
|
||||
} else if (fsDepthClamp) {
|
||||
WRITE(p, " gl_FragDepth = clamp(projZ, 0.0, 65536.0) / 65536.0;\n");
|
||||
WRITE(p, " gl_FragDepth = clamp(projZ, 0.0, 65535.0) / 65535.0;\n");
|
||||
} else if (useDiscardStencilBugWorkaround) {
|
||||
// Adreno and some Mali drivers apply early frag tests even with discard in the shader,
|
||||
// when only stencil is used. The exact situation seems to vary by driver.
|
||||
|
||||
@@ -234,9 +234,7 @@ StencilValueType ReplaceAlphaWithStencilType() {
|
||||
|
||||
case GE_FORMAT_4444:
|
||||
case GE_FORMAT_8888:
|
||||
case GE_FORMAT_INVALID:
|
||||
case GE_FORMAT_DEPTH16:
|
||||
case GE_FORMAT_CLUT8:
|
||||
default:
|
||||
switch (gstate.getStencilOpZPass()) {
|
||||
case GE_STENCILOP_REPLACE:
|
||||
// TODO: Could detect zero here and force ZERO - less uniform updates?
|
||||
@@ -246,10 +244,10 @@ StencilValueType ReplaceAlphaWithStencilType() {
|
||||
return STENCIL_VALUE_ZERO;
|
||||
|
||||
case GE_STENCILOP_DECR:
|
||||
return gstate_c.framebufFormat == GE_FORMAT_4444 ? STENCIL_VALUE_DECR_4 : STENCIL_VALUE_DECR_8;
|
||||
return gstate_c.framebufFormat == GE_FORMAT_4444 ? STENCIL_VALUE_DECR_4BIT : STENCIL_VALUE_DECR_8BIT;
|
||||
|
||||
case GE_STENCILOP_INCR:
|
||||
return gstate_c.framebufFormat == GE_FORMAT_4444 ? STENCIL_VALUE_INCR_4 : STENCIL_VALUE_INCR_8;
|
||||
return gstate_c.framebufFormat == GE_FORMAT_4444 ? STENCIL_VALUE_INCR_4BIT : STENCIL_VALUE_INCR_8BIT;
|
||||
|
||||
case GE_STENCILOP_INVERT:
|
||||
return STENCIL_VALUE_INVERT;
|
||||
@@ -784,16 +782,16 @@ void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithS
|
||||
// We're not blending, but we may still want to "blend" for stencil.
|
||||
// This is only useful for INCR/DECR/INVERT. Others can write directly.
|
||||
switch (stencilType) {
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_INCR_4BIT:
|
||||
case STENCIL_VALUE_INCR_8BIT:
|
||||
// We'll add the incremented value output by the shader.
|
||||
blendState.blendEnabled = true;
|
||||
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ONE);
|
||||
blendState.setEquation(blendEq, BlendEq::ADD);
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
case STENCIL_VALUE_DECR_4BIT:
|
||||
case STENCIL_VALUE_DECR_8BIT:
|
||||
// We'll subtract the incremented value output by the shader.
|
||||
blendState.blendEnabled = true;
|
||||
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ONE);
|
||||
@@ -986,13 +984,13 @@ static void ConvertBlendState(GenericBlendState &blendState, FBReadSetting useFB
|
||||
constantAlpha = gstate.getStencilTestRef();
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
case STENCIL_VALUE_INCR_4BIT:
|
||||
case STENCIL_VALUE_DECR_4BIT:
|
||||
constantAlpha = 16;
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
case STENCIL_VALUE_INCR_8BIT:
|
||||
case STENCIL_VALUE_DECR_8BIT:
|
||||
constantAlpha = 1;
|
||||
break;
|
||||
|
||||
@@ -1122,14 +1120,14 @@ static void ConvertBlendState(GenericBlendState &blendState, FBReadSetting useFB
|
||||
if (replaceAlphaWithStencil != REPLACE_ALPHA_NO) {
|
||||
// Let the fragment shader take care of it.
|
||||
switch (ReplaceAlphaWithStencilType()) {
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_INCR_4BIT:
|
||||
case STENCIL_VALUE_INCR_8BIT:
|
||||
// We'll add the increment value.
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
case STENCIL_VALUE_DECR_4BIT:
|
||||
case STENCIL_VALUE_DECR_8BIT:
|
||||
// Like add with a small value, but subtracting.
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
|
||||
alphaEq = BlendEq::SUBTRACT;
|
||||
@@ -1167,13 +1165,13 @@ static void ConvertBlendState(GenericBlendState &blendState, FBReadSetting useFB
|
||||
// This won't give a correct value (it multiplies) but it may be better than random values.
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ZERO);
|
||||
break;
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_INCR_4BIT:
|
||||
case STENCIL_VALUE_INCR_8BIT:
|
||||
// This won't give a correct value always, but it will try to increase at least.
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ONE);
|
||||
break;
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
case STENCIL_VALUE_DECR_4BIT:
|
||||
case STENCIL_VALUE_DECR_8BIT:
|
||||
// This won't give a correct value always, but it will try to decrease at least.
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ONE);
|
||||
alphaEq = BlendEq::SUBTRACT;
|
||||
|
||||
@@ -14,10 +14,10 @@ enum StencilValueType {
|
||||
STENCIL_VALUE_ONE,
|
||||
STENCIL_VALUE_KEEP,
|
||||
STENCIL_VALUE_INVERT,
|
||||
STENCIL_VALUE_INCR_4,
|
||||
STENCIL_VALUE_INCR_8,
|
||||
STENCIL_VALUE_DECR_4,
|
||||
STENCIL_VALUE_DECR_8,
|
||||
STENCIL_VALUE_INCR_4BIT,
|
||||
STENCIL_VALUE_INCR_8BIT,
|
||||
STENCIL_VALUE_DECR_4BIT,
|
||||
STENCIL_VALUE_DECR_8BIT,
|
||||
};
|
||||
|
||||
enum ReplaceAlphaType {
|
||||
|
||||
@@ -236,10 +236,10 @@ std::string FragmentShaderDesc(const FShaderID &id) {
|
||||
case STENCIL_VALUE_ONE: desc << "Sten1 "; break;
|
||||
case STENCIL_VALUE_KEEP: desc << "StenKeep "; break;
|
||||
case STENCIL_VALUE_INVERT: desc << "StenInv "; break;
|
||||
case STENCIL_VALUE_INCR_4: desc << "StenIncr4 "; break;
|
||||
case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;
|
||||
case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;
|
||||
case STENCIL_VALUE_DECR_8: desc << "StenDecr8 "; break;
|
||||
case STENCIL_VALUE_INCR_4BIT: desc << "StenIncr4 "; break;
|
||||
case STENCIL_VALUE_INCR_8BIT: desc << "StenIncr8 "; break;
|
||||
case STENCIL_VALUE_DECR_4BIT: desc << "StenDecr4 "; break;
|
||||
case STENCIL_VALUE_DECR_8BIT: desc << "StenDecr8 "; break;
|
||||
default: desc << "StenUnknown "; break;
|
||||
}
|
||||
} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
|
||||
|
||||
@@ -92,7 +92,7 @@ static bool GetBestFramebufferCandidate(FramebufferManagerCommon *fbManager, con
|
||||
// These are Data::Format:: B4G4R4A4_PACK16, B5G6R6_PACK16, B5G5R5A1_PACK16, R8G8B8A8
|
||||
|
||||
TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw, Draw2D *draw2D)
|
||||
: draw_(draw), draw2D_(draw2D), replacer_(draw), textureShaderCache_(draw, draw2D_) {
|
||||
: draw_(draw), draw2D_(draw2D), replacer_(draw), textureShaderCache_(draw, draw2D_), clutTextureCache_(draw) {
|
||||
decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL;
|
||||
|
||||
// It's only possible to have 1KB of palette entries, although we allow 2KB in a hack.
|
||||
|
||||
@@ -396,6 +396,11 @@ public:
|
||||
return videos_;
|
||||
}
|
||||
|
||||
// For the debugger
|
||||
const VirtualFramebuffer *NextFramebufferTexture() const {
|
||||
return nextFramebufferTexture_;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
|
||||
class ClutTextureCache {
|
||||
public:
|
||||
ClutTextureCache(Draw::DrawContext *draw) : draw_(draw) {}
|
||||
ClutTexture GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, const u32 *rawClut);
|
||||
|
||||
void Clear();
|
||||
@@ -47,7 +48,7 @@ public:
|
||||
void DeviceRestore(Draw::DrawContext *draw);
|
||||
|
||||
private:
|
||||
Draw::DrawContext *draw_;
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
std::unordered_map<u32, ClutTexture *> texCache_;
|
||||
};
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ static constexpr VkStencilOp stencilOps[] = {
|
||||
VK_STENCIL_OP_ZERO,
|
||||
VK_STENCIL_OP_REPLACE,
|
||||
VK_STENCIL_OP_INVERT,
|
||||
VK_STENCIL_OP_INCREMENT_AND_CLAMP,
|
||||
VK_STENCIL_OP_INCREMENT_AND_CLAMP, // TODO: Are we sure we shouldn't wrap?
|
||||
VK_STENCIL_OP_DECREMENT_AND_CLAMP,
|
||||
VK_STENCIL_OP_KEEP, // reserved
|
||||
VK_STENCIL_OP_KEEP, // reserved
|
||||
|
||||
+62
-18
@@ -591,7 +591,7 @@ void ImGePixelViewer::UpdateTexture(Draw::DrawContext *draw) {
|
||||
|
||||
ImGeReadbackViewer::ImGeReadbackViewer() {
|
||||
// These are only forward declared in the header, so we initialize them here.
|
||||
aspect = Draw::Aspect::COLOR_BIT;
|
||||
aspect_ = Draw::Aspect::COLOR_BIT;
|
||||
readbackFmt_ = Draw::DataFormat::UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ bool ImGeReadbackViewer::Draw(GPUCommon *gpuDebug, Draw::DrawContext *draw, floa
|
||||
int w = vfb->fbo->Width();
|
||||
int h = vfb->fbo->Height();
|
||||
int rbBpp = 4;
|
||||
switch (aspect) {
|
||||
switch (aspect_) {
|
||||
case Draw::Aspect::COLOR_BIT:
|
||||
readbackFmt_ = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
break;
|
||||
@@ -645,7 +645,7 @@ bool ImGeReadbackViewer::Draw(GPUCommon *gpuDebug, Draw::DrawContext *draw, floa
|
||||
}
|
||||
|
||||
data_ = new uint8_t[w * h * rbBpp];
|
||||
draw->CopyFramebufferToMemory(vfb->fbo, aspect, 0, 0, w, h, readbackFmt_, data_, w, Draw::ReadbackMode::BLOCK, "debugger");
|
||||
draw->CopyFramebufferToMemory(vfb->fbo, aspect_, 0, 0, w, h, readbackFmt_, data_, w, Draw::ReadbackMode::BLOCK, "debugger");
|
||||
|
||||
if (texture_) {
|
||||
texture_->Release();
|
||||
@@ -653,9 +653,12 @@ bool ImGeReadbackViewer::Draw(GPUCommon *gpuDebug, Draw::DrawContext *draw, floa
|
||||
}
|
||||
|
||||
// For now, we just draw the color texture. The others we convert.
|
||||
if (aspect != Draw::Aspect::COLOR_BIT) {
|
||||
if (aspect_ != Draw::Aspect::COLOR_BIT || showAlpha_) {
|
||||
uint8_t *texData = data_;
|
||||
if (aspect == Draw::Aspect::DEPTH_BIT && scale != 1.0f) {
|
||||
memset(histogram_, 0, sizeof(histogram_));
|
||||
Draw::DataFormat fmt = rbBpp == 1 ? Draw::DataFormat::R8_UNORM : Draw::DataFormat::R32_FLOAT;
|
||||
|
||||
if (aspect_ == Draw::Aspect::DEPTH_BIT && scale != 1.0f) {
|
||||
texData = new uint8_t[w * h * rbBpp];
|
||||
// Apply scale
|
||||
float *ptr = (float *)data_;
|
||||
@@ -663,9 +666,28 @@ bool ImGeReadbackViewer::Draw(GPUCommon *gpuDebug, Draw::DrawContext *draw, floa
|
||||
for (int i = 0; i < w * h; i++) {
|
||||
tptr[i] = ptr[i] * scale;
|
||||
}
|
||||
} else if (aspect_ == Draw::Aspect::STENCIL_BIT) {
|
||||
for (int i = 0; i < w * h; i++) {
|
||||
histogram_[data_[i]]++;
|
||||
}
|
||||
} else if (aspect_ == Draw::Aspect::COLOR_BIT && showAlpha_) {
|
||||
// Build a histogram of alpha values.
|
||||
for (int i = 0; i < w * h; i++) {
|
||||
histogram_[data_[i * 4 + 3]]++;
|
||||
}
|
||||
texData = new uint8_t[w * h * rbBpp];
|
||||
// Also, tweak the pixels to actually show alpha as grayscale.
|
||||
for (int i = 0; i < w * h; i++) {
|
||||
uint8_t alpha = data_[i * 4 + 3];
|
||||
texData[i * 4 + 0] = alpha;
|
||||
texData[i * 4 + 1] = alpha;
|
||||
texData[i * 4 + 2] = alpha;
|
||||
texData[i * 4 + 3] = 255;
|
||||
}
|
||||
|
||||
fmt = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
}
|
||||
|
||||
Draw::DataFormat fmt = rbBpp == 1 ? Draw::DataFormat::R8_UNORM : Draw::DataFormat::R32_FLOAT;
|
||||
Draw::TextureDesc desc{ Draw::TextureType::LINEAR2D,
|
||||
fmt,
|
||||
(int)w,
|
||||
@@ -710,7 +732,11 @@ bool ImGeReadbackViewer::FormatValueAt(char *buf, size_t bufSize, int x, int y)
|
||||
case Draw::DataFormat::R8G8B8A8_UNORM:
|
||||
{
|
||||
const uint32_t *read32 = (const uint32_t *)(data_ + offset);
|
||||
snprintf(buf, bufSize, "%08x", *read32);
|
||||
int r = (*read32 >> 0) & 0xFF;
|
||||
int g = (*read32 >> 8) & 0xFF;
|
||||
int b = (*read32 >> 16) & 0xFF;
|
||||
int a = (*read32 >> 24) & 0xFF;
|
||||
snprintf(buf, bufSize, "%08x (RGBA %d, %d, %d, %d)", *read32, r, g, b, a);
|
||||
return true;
|
||||
}
|
||||
case Draw::DataFormat::D32F:
|
||||
@@ -728,6 +754,8 @@ bool ImGeReadbackViewer::FormatValueAt(char *buf, size_t bufSize, int x, int y)
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
_dbg_assert_(false);
|
||||
snprintf(buf, bufSize, "N/A");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1054,7 +1082,7 @@ void ImGeDebuggerWindow::NotifyStep() {
|
||||
rbViewer_.fbAddr = gstate.getFrameBufAddress();
|
||||
rbViewer_.fbStride = gstate.FrameBufStride();
|
||||
rbViewer_.fbFormat = gstate.FrameBufFormat();
|
||||
rbViewer_.aspect = selectedAspect_;
|
||||
rbViewer_.aspect_ = selectedAspect_;
|
||||
}
|
||||
rbViewer_.Snapshot();
|
||||
}
|
||||
@@ -1272,7 +1300,12 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
}
|
||||
ImGui::SetNextItemWidth(200.0f);
|
||||
ImGui::SliderFloat("Zoom", &previewZoom_, 0.125f, 2.f, "%.3f", ImGuiSliderFlags_Logarithmic);
|
||||
|
||||
if (selectedAspect_ == Draw::Aspect::COLOR_BIT) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Alpha", &rbViewer_.showAlpha_)) {
|
||||
rbViewer_.Snapshot();
|
||||
}
|
||||
}
|
||||
// Use selectable instead of tab bar so we can get events (haven't figured that out).
|
||||
static const Draw::Aspect aspects[3] = { Draw::Aspect::COLOR_BIT, Draw::Aspect::DEPTH_BIT, Draw::Aspect::STENCIL_BIT, };
|
||||
static const char *const aspectNames[3] = { "Color", "Depth", "Stencil" };
|
||||
@@ -1329,8 +1362,8 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
drawList->PopClipRect();
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
int x = (int)(ImGui::GetMousePos().x - p0.x) * previewZoom_;
|
||||
int y = (int)(ImGui::GetMousePos().y - p0.y) * previewZoom_;
|
||||
int x = (int)(ImGui::GetMousePos().x - p0.x) / previewZoom_;
|
||||
int y = (int)(ImGui::GetMousePos().y - p0.y) / previewZoom_;
|
||||
char temp[128];
|
||||
if (lookup->FormatValueAt(temp, sizeof(temp), x, y)) {
|
||||
ImGui::Text("(%d, %d): %s", x, y, temp);
|
||||
@@ -1341,6 +1374,13 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
ImGui::TextUnformatted("(no pixel hovered)");
|
||||
}
|
||||
|
||||
if (lookup->GetHistogramSize() > 0) {
|
||||
ImGui::PlotHistogram("##histogram", [](void *data, int idx) -> float {
|
||||
PixelLookup *lookup = static_cast<PixelLookup *>(data);
|
||||
return lookup->GetHistogramValue(idx);
|
||||
}, lookup, 256, 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, 80));
|
||||
}
|
||||
|
||||
if (vfb && vfb->fbo) {
|
||||
ImGui::Text("VFB %dx%d (emulated: %dx%d)", vfb->width, vfb->height, vfb->fbo->Width(), vfb->fbo->Height());
|
||||
} else {
|
||||
@@ -1352,9 +1392,8 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
ImGui::Text("(clear mode - texturing not used)");
|
||||
} else if (!gstate.isTextureMapEnabled()) {
|
||||
ImGui::Text("(texturing not enabled");
|
||||
} else { // We don't bother with the texture if previewCmd is BOUNDING_BOX - no texturing happens there.
|
||||
TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon();
|
||||
TexCacheEntry *tex = texcache ? texcache->SetTexture() : nullptr;
|
||||
} else if (TextureCacheCommon *texcache = gpuDebug->GetTextureCacheCommon()) { // We don't bother with the texture if previewCmd is BOUNDING_BOX - no texturing happens there.
|
||||
const TexCacheEntry *tex = texcache->SetTexture();
|
||||
if (tex) {
|
||||
ImGui::Text("Texture: %08x", tex->addr);
|
||||
texcache->ApplyTexture(false, false);
|
||||
@@ -1362,8 +1401,8 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
void *nativeView = texcache->GetNativeTextureView(tex, true);
|
||||
ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView);
|
||||
|
||||
float texW = dimWidth(tex->dim);
|
||||
float texH = dimHeight(tex->dim);
|
||||
const float texW = dimWidth(tex->dim);
|
||||
const float texH = dimHeight(tex->dim);
|
||||
|
||||
const ImVec2 p0 = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 sz = ImGui::GetContentRegionAvail();
|
||||
@@ -1382,11 +1421,16 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
} else if (const VirtualFramebuffer *fb = texcache->NextFramebufferTexture()) {
|
||||
// A framebuffer.
|
||||
// TODO: More detail here.
|
||||
ImGui::Text("Framebuffer as texture: %08x", fb->fb_address);
|
||||
} else {
|
||||
ImGui::Text("(no valid texture bound)");
|
||||
// In software mode, we should just decode the texture here.
|
||||
// TODO: List some of the texture params here.
|
||||
}
|
||||
} else {
|
||||
// Software mode?
|
||||
ImGui::Text("(texture cache not available)");
|
||||
}
|
||||
|
||||
// Let's display the current CLUT.
|
||||
|
||||
+15
-1
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "Common/GPU/thin3d.h"
|
||||
|
||||
// GE-related windows of the ImDebugger
|
||||
|
||||
@@ -63,6 +64,8 @@ public:
|
||||
virtual ~PixelLookup() {}
|
||||
|
||||
virtual bool FormatValueAt(char *buf, size_t bufSize, int x, int y) const = 0;
|
||||
virtual float GetHistogramValue(int idx) const = 0;
|
||||
virtual int GetHistogramSize() const = 0;
|
||||
};
|
||||
|
||||
struct ImGePixelViewer : public PixelLookup {
|
||||
@@ -73,6 +76,8 @@ struct ImGePixelViewer : public PixelLookup {
|
||||
}
|
||||
bool FormatValueAt(char *buf, size_t bufSize, int x, int y) const override;
|
||||
void DeviceLost();
|
||||
float GetHistogramValue(int idx) const override { return 0; }
|
||||
int GetHistogramSize() const override { return 0; }
|
||||
|
||||
uint32_t addr = 0x04110000;
|
||||
uint16_t stride = 512;
|
||||
@@ -108,11 +113,20 @@ struct ImGeReadbackViewer : public PixelLookup {
|
||||
GEBufferFormat fbFormat = GE_FORMAT_INVALID;
|
||||
|
||||
// This specifies what to show
|
||||
Draw::Aspect aspect;
|
||||
Draw::Aspect aspect_{};
|
||||
bool showAlpha_ = false;
|
||||
float scale = 1.0f; // Scales depth values.
|
||||
|
||||
const int *Histogram() const { return histogram_; }
|
||||
float GetHistogramValue(int idx) const override {
|
||||
return histogram_[idx];
|
||||
}
|
||||
float GetHistogramMaxValue() const { return histogramMax_; }
|
||||
int GetHistogramSize() const override { return aspect_ == Draw::Aspect::STENCIL_BIT ? 256 : (aspect_ == Draw::Aspect::COLOR_BIT && showAlpha_ ? 256 : 0); }
|
||||
private:
|
||||
uint8_t *data_ = nullptr;
|
||||
int histogram_[256 * 3] = {};
|
||||
int histogramMax_ = 0;
|
||||
Draw::DataFormat readbackFmt_;
|
||||
Draw::Texture *texture_ = nullptr;
|
||||
bool dirty_ = true;
|
||||
|
||||
@@ -975,12 +975,14 @@ bool CreateGlobalPipelines() {
|
||||
|
||||
colorPipeline = g_draw->CreateGraphicsPipeline(colorDesc, "global_color");
|
||||
if (!colorPipeline) {
|
||||
_dbg_assert_(false);
|
||||
// Something really critical is wrong, don't care much about correct releasing of the states.
|
||||
return false;
|
||||
}
|
||||
|
||||
texColorPipeline = g_draw->CreateGraphicsPipeline(texColorDesc, "global_texcolor");
|
||||
if (!texColorPipeline) {
|
||||
_dbg_assert_(false);
|
||||
// Something really critical is wrong, don't care much about correct releasing of the states.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ ULES00785 = true
|
||||
ULJS00242 = true
|
||||
|
||||
[PixelDepthRounding]
|
||||
|
||||
# Heroes Phantasia requires pixel depth rounding. #6485 (flickering overlaid sprites)
|
||||
NPJH50558 = true
|
||||
ULJS00456 = true
|
||||
|
||||
@@ -34,7 +34,7 @@ struct RegisteredTexture {
|
||||
struct BackendData {
|
||||
Draw::SamplerState *fontSampler = nullptr;
|
||||
Draw::Texture *fontImage = nullptr;
|
||||
Draw::Pipeline *pipelines[2]{};
|
||||
Draw::Pipeline *pipelines[(int)ImGuiPipeline::Count]{};
|
||||
std::vector<RegisteredTexture> tempTextures;
|
||||
};
|
||||
|
||||
@@ -220,12 +220,9 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
||||
DepthStencilState *depthStencil = draw->CreateDepthStencilState(dsDesc);
|
||||
RasterState *rasterNoCull = draw->CreateRasterState({});
|
||||
|
||||
ShaderModule *vs_texture_color_2d = draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D);
|
||||
ShaderModule *fs_texture_color_2d = draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D);
|
||||
|
||||
PipelineDesc pipelineDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ vs_texture_color_2d, fs_texture_color_2d },
|
||||
{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D_NO_TINT), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
|
||||
inputLayout,
|
||||
depthStencil,
|
||||
blend,
|
||||
@@ -233,9 +230,13 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
|
||||
&vsTexColBufDesc
|
||||
};
|
||||
|
||||
bd->pipelines[0] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline");
|
||||
bd->pipelines[(int)ImGuiPipeline::TexturedAlphaBlend] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline");
|
||||
pipelineDesc.blend = blendOpaque;
|
||||
bd->pipelines[1] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline-opaque");
|
||||
bd->pipelines[(int)ImGuiPipeline::TexturedOpaque] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline-opaque");
|
||||
|
||||
pipelineDesc.shaders[1] = draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D_ALPHA_TO_GRAY);
|
||||
|
||||
bd->pipelines[(int)ImGuiPipeline::TexturedAlphaToGrayscale] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline-alpha-to-gray");
|
||||
|
||||
inputLayout->Release();
|
||||
blend->Release();
|
||||
|
||||
@@ -46,6 +46,8 @@ IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects();
|
||||
enum class ImGuiPipeline {
|
||||
TexturedAlphaBlend = 0,
|
||||
TexturedOpaque = 1,
|
||||
TexturedAlphaToGrayscale = 2,
|
||||
Count,
|
||||
};
|
||||
|
||||
// These register a texture for imgui drawing, but just for the current frame.
|
||||
|
||||
Reference in New Issue
Block a user