Merge pull request #15754 from hrydgard/unify-stencil-draw

Unify stencil upload using thin3d
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2022-08-03 14:11:35 +02:00
commit 4e4ccbd819
36 files changed
+459 -864

No files matched your search

-4
View File
@@ -1455,7 +1455,6 @@ set(GPU_GLES
GPU/GLES/ShaderManagerGLES.h
GPU/GLES/StateMappingGLES.cpp
GPU/GLES/StateMappingGLES.h
GPU/GLES/StencilBufferGLES.cpp
GPU/GLES/TextureCacheGLES.cpp
GPU/GLES/TextureCacheGLES.h
GPU/GLES/DrawEngineGLES.cpp
@@ -1479,7 +1478,6 @@ set(GPU_VULKAN
GPU/Vulkan/ShaderManagerVulkan.h
GPU/Vulkan/StateMappingVulkan.cpp
GPU/Vulkan/StateMappingVulkan.h
GPU/Vulkan/StencilBufferVulkan.cpp
GPU/Vulkan/TextureCacheVulkan.cpp
GPU/Vulkan/TextureCacheVulkan.h
GPU/Vulkan/VulkanUtil.cpp
@@ -1499,7 +1497,6 @@ set(GPU_D3D9
GPU/Directx9/ShaderManagerDX9.h
GPU/Directx9/StateMappingDX9.cpp
GPU/Directx9/StateMappingDX9.h
GPU/Directx9/StencilBufferDX9.cpp
GPU/Directx9/TextureCacheDX9.cpp
GPU/Directx9/TextureCacheDX9.h
)
@@ -1519,7 +1516,6 @@ set(GPU_D3D11
GPU/D3D11/ShaderManagerD3D11.h
GPU/D3D11/StateMappingD3D11.cpp
GPU/D3D11/StateMappingD3D11.h
GPU/D3D11/StencilBufferD3D11.cpp
GPU/D3D11/TextureCacheD3D11.cpp
GPU/D3D11/TextureCacheD3D11.h
)
+17 -5
View File
@@ -38,6 +38,7 @@ class D3D11Pipeline;
class D3D11BlendState;
class D3D11DepthStencilState;
class D3D11SamplerState;
class D3D11Buffer;
class D3D11RasterState;
class D3D11Framebuffer;
@@ -248,10 +249,12 @@ private:
uint8_t stencilRef_ = 0;
uint8_t stencilWriteMask_ = 0xFF;
uint8_t stencilCompareMask_ = 0xFF;
bool stencilDirty_ = true;
// Temporaries
ID3D11Texture2D *packTexture_ = nullptr;
Buffer *upBuffer_ = nullptr;
// System info
D3D_FEATURE_LEVEL featureLevel_;
@@ -282,8 +285,9 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
caps_.framebufferBlitSupported = false;
caps_.framebufferCopySupported = true;
caps_.framebufferDepthBlitSupported = false;
caps_.framebufferStencilBlitSupported = false;
caps_.framebufferDepthCopySupported = true;
caps_.framebufferSeparateDepthCopySupported = false;
caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw.
caps_.texture3DSupported = true;
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
@@ -338,9 +342,14 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
_assert_(SUCCEEDED(hr));
shaderLanguageDesc_.Init(HLSL_D3D11);
const size_t UP_MAX_BYTES = 65536 * 24;
upBuffer_ = CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
}
D3D11DrawContext::~D3D11DrawContext() {
upBuffer_->Release();
packTexture_->Release();
// Release references.
@@ -756,9 +765,6 @@ public:
shaderModule->Release();
}
}
bool RequiresBuffer() override {
return true;
}
AutoRef<D3D11InputLayout> input;
ID3D11InputLayout *il = nullptr;
@@ -1248,7 +1254,13 @@ void D3D11DrawContext::DrawIndexed(int indexCount, int offset) {
void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) {
ApplyCurrentState();
// TODO: Upload the data then draw..
int byteSize = vertexCount * curPipeline_->input->strides[0];
UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, byteSize, Draw::UPDATE_DISCARD);
BindVertexBuffers(0, 1, &upBuffer_, nullptr);
int offset = 0;
Draw(vertexCount, offset);
}
uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const {
+6 -3
View File
@@ -23,6 +23,7 @@
#include "Common/Math/lin/matrix4x4.h"
#include "Common/GPU/thin3d.h"
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
@@ -272,9 +273,6 @@ public:
D3D9Pipeline() {}
~D3D9Pipeline() {
}
bool RequiresBuffer() override {
return false;
}
D3D9ShaderModule *vshader;
D3D9ShaderModule *pshader;
@@ -666,6 +664,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
caps_.framebufferBlitSupported = true;
caps_.framebufferCopySupported = false;
caps_.framebufferDepthBlitSupported = true;
caps_.framebufferStencilBlitSupported = false;
caps_.framebufferDepthCopySupported = false;
caps_.framebufferSeparateDepthCopySupported = false;
caps_.texture3DSupported = true;
@@ -1065,6 +1064,10 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si
// No D3D9-compatible shader compiler installed.
error = "D3D9 shader compiler not installed";
}
ERROR_LOG(G3D, "Compile error: %s", error);
ERROR_LOG(G3D, "%s", LineNumberString(std::string((const char *)data)).c_str());
OutputDebugStringA(source);
OutputDebugStringA(error);
if (errorBuffer)
+2 -8
View File
@@ -261,9 +261,6 @@ public:
~OpenGLInputLayout();
void Compile(const InputLayoutDesc &desc);
bool RequiresBuffer() {
return false;
}
GLRInputLayout *inputLayout_ = nullptr;
int stride = 0;
@@ -284,10 +281,6 @@ public:
bool LinkShaders();
bool RequiresBuffer() override {
return inputLayout && inputLayout->RequiresBuffer();
}
GLuint prim = 0;
std::vector<OpenGLShaderModule *> shaders;
AutoRef<OpenGLInputLayout> inputLayout;
@@ -545,6 +538,7 @@ OpenGLContext::OpenGLContext() {
caps_.framebufferCopySupported = gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image;
caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3;
caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported;
caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported;
caps_.depthClampSupported = gl_extensions.ARB_depth_clamp;
if (gl_extensions.IsGLES) {
caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance;
@@ -1119,7 +1113,7 @@ void OpenGLContext::ApplySamplers() {
const OpenGLSamplerState *samp = boundSamplers_[i];
const GLRTexture *tex = boundTextures_[i];
if (tex) {
_assert_(samp);
_assert_msg_(samp, "Sampler missing");
} else {
continue;
}
+2
View File
@@ -86,12 +86,14 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) {
texelFetch = "texelFetch";
forceMatrix4x4 = false;
coefsFromBuffers = true;
vertexIndex = true;
break;
case HLSL_D3D9:
case HLSL_D3D11:
if (lang == HLSL_D3D11) {
fragColor0 = "outfragment.target";
fragColor1 = "outfragment.target1";
vertexIndex = true; // if declared as a semantic input
} else {
fragColor0 = "outfragment.target";
}
+2
View File
@@ -52,6 +52,8 @@ struct ShaderLanguageDesc {
const char *framebufferFetchExtension = nullptr;
const char *vsOutPrefix = "";
const char *viewportYSign = "";
bool vertexIndex = false;
bool glslES30 = false; // really glslES30Features. TODO: Clean this up.
bool bitwiseOps = false;
bool forceMatrix4x4 = false;
+34 -2
View File
@@ -162,6 +162,11 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniform
if (lang_.shaderLanguage == HLSL_D3D11) {
C("uint gl_VertexIndex : SV_VertexID, ");
}
// List the inputs.
for (auto &input : inputs) {
F("in %s %s : %s, ", input.type, input.name, input.semantic);
}
Rewind(2); // Get rid of the last comma.
C(") {\n");
C(" vec4 gl_Position;\n");
@@ -171,13 +176,23 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniform
break;
}
case GLSL_VULKAN:
{
int i = 0;
for (auto &input : inputs) {
F("layout(location = %d) in %s %s;\n", i, input.type, input.name);
i++;
}
for (auto &varying : varyings) {
F("layout(location = %d) %s out %s %s; // %s\n",
varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic);
}
C("void main() {\n");
break;
}
default: // OpenGL
for (auto &input : inputs) {
F("in %s %s;\n", input.type, input.name);
}
for (auto &varying : varyings) {
F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic, varying.index);
}
@@ -191,10 +206,15 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> var
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
if (!uniforms.is_empty()) {
C("cbuffer base : register(b0) {\n");
for (auto &uniform : uniforms) {
//F(" %s %s : %s;\n", uniform.type, uniform.name, uniform.index);
F(" %s %s;\n", uniform.type, uniform.name);
}
C("};\n");
}
// Let's do the varyings as parameters to main, no struct.
C("vec4 main(");
for (auto &varying : varyings) {
@@ -224,12 +244,23 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> var
F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic);
}
C("layout(location = 0, index = 0) out vec4 fragColor0;\n");
if (!uniforms.is_empty()) {
C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n");
for (auto &uniform : uniforms) {
F("%s %s;\n", uniform.type, uniform.name);
}
C("};\n");
}
C("\nvoid main() {\n");
break;
default:
default: // GLSL OpenGL
for (auto &varying : varyings) {
F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic);
}
for (auto &uniform : uniforms) {
F("uniform %s %s;\n", uniform.type, uniform.name);
}
if (!strcmp(lang_.fragColor0, "fragColor0")) {
C("out vec4 fragColor0;\n");
}
@@ -284,6 +315,7 @@ void ShaderWriter::DeclareTexture2D(const char *name, int binding) {
F("Texture2D<float4> %s : register(t%d);\n", name, binding);
break;
case HLSL_D3D9:
F("sampler %s: register(s%d);\n", name, binding);
break;
case GLSL_VULKAN:
// In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1.
+1
View File
@@ -19,6 +19,7 @@
struct InputDef {
const char *type;
const char *name;
const char *semantic;
};
struct UniformDef {
+1 -3
View File
@@ -271,9 +271,6 @@ public:
int GetUBOSize() const {
return uboSize_;
}
bool RequiresBuffer() override {
return false;
}
VkPipeline backbufferPipeline = VK_NULL_HANDLE;
VkPipeline framebufferPipeline = VK_NULL_HANDLE;
@@ -787,6 +784,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
caps_.framebufferBlitSupported = true;
caps_.framebufferCopySupported = true;
caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat;
caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported;
caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case.
caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case.
caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan.
+5 -5
View File
@@ -25,7 +25,7 @@ namespace Draw {
// Useful in UBOs
typedef int bool32;
enum class Comparison : int {
enum class Comparison : uint8_t {
NEVER,
LESS,
EQUAL,
@@ -37,7 +37,7 @@ enum class Comparison : int {
};
// Had to prefix with LOGIC, too many clashes
enum class LogicOp : int {
enum class LogicOp : uint8_t {
LOGIC_CLEAR,
LOGIC_SET,
LOGIC_COPY,
@@ -56,7 +56,7 @@ enum class LogicOp : int {
LOGIC_OR_INVERTED,
};
enum class BlendOp : int {
enum class BlendOp : uint8_t {
ADD,
SUBTRACT,
REV_SUBTRACT,
@@ -96,7 +96,7 @@ enum class StencilOp {
DECREMENT_AND_WRAP = 7,
};
enum class TextureFilter : int {
enum class TextureFilter : uint8_t {
NEAREST = 0,
LINEAR = 1,
};
@@ -450,7 +450,6 @@ public:
class Pipeline : public RefCountedObject {
public:
virtual ~Pipeline() {}
virtual bool RequiresBuffer() = 0;
};
class RasterState : public RefCountedObject {};
@@ -534,6 +533,7 @@ struct DeviceCaps {
bool framebufferDepthCopySupported;
bool framebufferSeparateDepthCopySupported;
bool framebufferDepthBlitSupported;
bool framebufferStencilBlitSupported;
bool framebufferFetchSupported;
bool texture3DSupported;
+1 -18
View File
@@ -32,12 +32,6 @@ void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) {
draw_ = t3d;
inited_ = true;
if (pipeline->RequiresBuffer()) {
vbuf_ = draw_->CreateBuffer(MAX_VERTS * sizeof(Vertex), BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
} else {
vbuf_ = nullptr;
}
}
Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) {
@@ -57,10 +51,6 @@ Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) {
}
void DrawBuffer::Shutdown() {
if (vbuf_) {
vbuf_->Release();
vbuf_ = nullptr;
}
inited_ = false;
alphaStack_.clear();
drawMatrixStack_.clear();
@@ -90,14 +80,7 @@ void DrawBuffer::Flush(bool set_blend_state) {
ub.tint = tint_;
ub.saturation = saturation_;
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
if (vbuf_) {
draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_, Draw::UPDATE_DISCARD);
draw_->BindVertexBuffers(0, 1, &vbuf_, nullptr);
int offset = 0;
draw_->Draw(count_, offset);
} else {
draw_->DrawUP((const void *)verts_, count_);
}
draw_->DrawUP((const void *)verts_, count_);
count_ = 0;
}
-1
View File
@@ -199,7 +199,6 @@ private:
std::vector<float> alphaStack_;
Draw::DrawContext *draw_ = nullptr;
Draw::Buffer *vbuf_ = nullptr;
Draw::Pipeline *pipeline_ = nullptr;
Vertex *verts_;
+10
View File
@@ -35,6 +35,16 @@ enum {
DECODED_INDEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 16,
};
enum {
TEX_SLOT_PSP_TEXTURE = 0,
TEX_SLOT_SHADERBLEND_SRC = 1,
TEX_SLOT_ALPHATEST = 2,
TEX_SLOT_CLUT = 3,
TEX_SLOT_SPLINE_POINTS = 4,
TEX_SLOT_SPLINE_WEIGHTS_U = 5,
TEX_SLOT_SPLINE_WEIGHTS_V = 6,
};
inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) {
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
// into the top of the verttype where there are unused bits.
+5 -1
View File
@@ -469,7 +469,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) {
gpu->PerformMemoryUpload(params.fb_address, byteSize);
NotifyStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO);
PerformStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO);
// TODO: Is it worth trying to upload the depth buffer (only if it wasn't copied above..?)
}
@@ -2488,6 +2488,10 @@ void FramebufferManagerCommon::DeviceLost() {
DoRelease(reinterpretVBuf_);
DoRelease(reinterpretSampler_);
DoRelease(reinterpretVS_);
DoRelease(stencilUploadFs_);
DoRelease(stencilUploadVs_);
DoRelease(stencilUploadSampler_);
DoRelease(stencilUploadPipeline_);
presentation_->DeviceLost();
draw_ = nullptr;
}
+8 -2
View File
@@ -19,7 +19,6 @@
// Here's a list of functionality to unify into FramebufferManagerCommon:
// * DrawActiveTexture
// * BlitFramebuffer
// * StencilBuffer*.cpp
//
// Also, in TextureCache we should be able to unify texture-based depal.
@@ -253,7 +252,7 @@ public:
void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
void UpdateFromMemory(u32 addr, int size, bool safe);
void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0;
bool PerformStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR);
// Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it.
// In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless
// read framebuffers is on, in which case this should always return false).
@@ -467,4 +466,11 @@ protected:
Draw::ShaderModule *reinterpretVS_ = nullptr;
Draw::SamplerState *reinterpretSampler_ = nullptr;
Draw::Buffer *reinterpretVBuf_ = nullptr;
// Common implementation of stencil buffer upload. Also not 100% optimal, but not perforamnce
// critical either.
Draw::Pipeline *stencilUploadPipeline_ = nullptr;
Draw::ShaderModule *stencilUploadVs_ = nullptr;
Draw::ShaderModule *stencilUploadFs_ = nullptr;
Draw::SamplerState *stencilUploadSampler_ = nullptr;
};
+3 -2
View File
@@ -79,9 +79,10 @@ bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lan
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");
writer.F(" y *= %s1.0;\n", lang.viewportYSign);
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;
}
+281 -3
View File
@@ -15,9 +15,17 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/GPU/Shader.h"
#include "Common/GPU/ShaderWriter.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
for (u32 i = 0; i < numPixels / 2; ++i) {
@@ -28,7 +36,7 @@ u8 StencilBits5551(const u8 *ptr8, u32 numPixels) {
return 0;
}
u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
@@ -39,7 +47,7 @@ u8 StencilBits4444(const u8 *ptr8, u32 numPixels) {
return ((bits >> 12) & 0xF) | (bits >> 28);
}
u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
const u32 *ptr = (const u32 *)ptr8;
u32 bits = 0;
@@ -49,3 +57,273 @@ u8 StencilBits8888(const u8 *ptr8, u32 numPixels) {
return bits >> 24;
}
struct StencilUB {
float stencilValue;
};
const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), {
{ "stencilValue", -1, 0, UniformType::FLOAT1, 0 },
} };
// TODO: Merge this with UniformBufferDesc
static const UniformDef uniforms[1] = {
{ "float", "stencilValue", 0 },
};
static const InputDef inputs[1] = {
{ "vec2", "a_position", "POSITION", }
};
static const VaryingDef varyings[1] = {
{ "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" },
};
void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
writer.HighPrecisionFloat();
writer.DeclareSampler2D("samp", 0);
writer.DeclareTexture2D("tex", 0);
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
writer.C("layout (depth_unchanged) out float gl_FragDepth;\n");
}
writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n");
writer.BeginFSMain(uniforms, varyings);
writer.C(" vec4 index = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n");
writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a.
writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n");
// Bitwise operations on floats, ugh.
writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n");
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
writer.C(" gl_FragDepth = gl_FragCoord.z;\n");
}
writer.EndFSMain("outColor");
}
// This can probably be shared with some other shaders, like reinterpret or the future depth upload.
void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0);
writer.BeginVSMain(lang.vertexIndex ? Slice<InputDef>::empty() : inputs, Slice<UniformDef>::empty(), varyings);
if (lang.vertexIndex) {
writer.C(" float x = float((gl_VertexIndex & 1) << 1);\n");
writer.C(" float y = float(gl_VertexIndex & 2);\n");
writer.C(" v_texcoord = vec2(x, y);\n");
} else {
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);
}
bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilUpload flags) {
using namespace Draw;
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
}
VirtualFramebuffer *dstBuffer = 0;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
if (vfb->fb_address == addr) {
dstBuffer = vfb;
}
}
if (!dstBuffer) {
return false;
}
int values = 0;
u8 usedBits = 0;
const u8 *src = Memory::GetPointer(addr);
if (!src)
return false;
switch (dstBuffer->format) {
case GE_FORMAT_565:
// Well, this doesn't make much sense.
return false;
case GE_FORMAT_5551:
usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 2;
break;
case GE_FORMAT_4444:
usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 16;
break;
case GE_FORMAT_8888:
usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 256;
break;
case GE_FORMAT_INVALID:
case GE_FORMAT_DEPTH16:
// Inconceivable.
_assert_(false);
break;
}
if (usedBits == 0) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0.
// We're done.
return false;
}
shaderManager_->DirtyLastShader();
// Let's not bother with the shader if it's just zero.
if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Clear");
}
// Here we might want to clear destination alpha by using a draw, but we haven't found a need for this yet.
// Will implement when needed...
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE);
return true;
}
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
if (!stencilUploadPipeline_) {
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
char *fsCode = new char[4000];
char *vsCode = new char[4000];
GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs());
GenerateStencilVs(vsCode, shaderLanguageDesc);
stencilUploadFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs");
stencilUploadVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs");
_assert_(stencilUploadFs_ && stencilUploadVs_);
InputLayoutDesc desc = {
{
{ 8, false },
},
{
{ 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
},
};
InputLayout *inputLayout = draw_->CreateInputLayout(desc);
BlendState *blendOff = draw_->CreateBlendState({ false, 0x8 });
DepthStencilStateDesc dsDesc{};
dsDesc.stencilEnabled = true;
dsDesc.stencil.compareOp = Comparison::ALWAYS;
dsDesc.stencil.depthFailOp = StencilOp::REPLACE;
dsDesc.stencil.failOp = StencilOp::REPLACE;
dsDesc.stencil.passOp = StencilOp::REPLACE;
DepthStencilState *stencilWrite = draw_->CreateDepthStencilState(dsDesc);
RasterState *rasterNoCull = draw_->CreateRasterState({});
PipelineDesc stencilWriteDesc{
Primitive::TRIANGLE_LIST,
{ stencilUploadVs_, stencilUploadFs_ },
inputLayout, stencilWrite, blendOff, rasterNoCull, &stencilUBDesc,
};
stencilUploadPipeline_ = draw_->CreateGraphicsPipeline(stencilWriteDesc);
_assert_(stencilUploadPipeline_);
delete[] fsCode;
delete[] vsCode;
rasterNoCull->Release();
blendOff->Release();
stencilWrite->Release();
inputLayout->Release();
SamplerStateDesc descNearest{};
stencilUploadSampler_ = draw_->CreateSamplerState(descNearest);
}
// Fullscreen triangle coordinates.
static const float positions[6] = {
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
};
bool useBlit = draw_->GetDeviceCaps().framebufferStencilBlitSupported;
// Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x.
// Then after we're done, we'll just blit it across and stretch it there. Not worth doing
// if already at 1x size though, of course.
// TODO: This path means that we don't write color alpha... Ugh.
if (dstBuffer->width == dstBuffer->renderWidth || !dstBuffer->fbo) {
useBlit = false;
}
u16 w = useBlit ? dstBuffer->width : dstBuffer->renderWidth;
u16 h = useBlit ? dstBuffer->height : dstBuffer->renderHeight;
Draw::Framebuffer *blitFBO = nullptr;
if (useBlit) {
blitFBO = GetTempFBO(TempFBO::STENCIL, w, h);
draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Blit");
} else if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_NoBlit");
}
Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f };
draw_->SetViewports(1, &viewport);
// TODO: Switch the format to a single channel format?
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height);
if (!tex) {
// Bad!
return false;
}
draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex);
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilUploadSampler_);
// We must bind the program after starting the render pass, and set the color mask after clearing.
draw_->SetScissorRect(0, 0, w, h);
draw_->BindPipeline(stencilUploadPipeline_);
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
StencilUB ub{};
if (dstBuffer->format == GE_FORMAT_4444) {
draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF);
ub.stencilValue = i * (16.0f / 255.0f);
} else if (dstBuffer->format == GE_FORMAT_5551) {
draw_->SetStencilParams(0xFF, 0xFF, 0xFF);
ub.stencilValue = i * (128.0f / 255.0f);
} else {
draw_->SetStencilParams(0xFF, i, 0xFF);
ub.stencilValue = i * (1.0f / 255.0f);
}
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
draw_->DrawUP(positions, 3);
}
if (useBlit) {
// Note that scissors don't affect blits on other APIs than OpenGL, so might want to try to get rid of this.
draw_->SetScissorRect(0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight);
draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit");
RebindFramebuffer("RebindFramebuffer - Stencil");
}
tex->Release();
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
return true;
}
+5 -3
View File
@@ -2,6 +2,8 @@
#include "Common/CommonTypes.h"
u8 StencilBits8888(const u8 *ptr8, u32 numPixels);
u8 StencilBits4444(const u8 *ptr8, u32 numPixels);
u8 StencilBits5551(const u8 *ptr8, u32 numPixels);
#include "Common/GPU/thin3d.h"
// Exposed for automated tests
void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs);
void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang);
+1 -1
View File
@@ -207,7 +207,7 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float
coord[i].pos.y = -(coord[i].pos.y * invDestH - 1.0f);
}
if (g_display_rotation != DisplayRotation::ROTATE_0) {
if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) {
for (int i = 0; i < 4; i++) {
// backwards notation, should fix that...
coord[i].pos = coord[i].pos * g_display_rot_matrix;
-2
View File
@@ -43,8 +43,6 @@ public:
void EndFrame();
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
// TODO: Remove
ID3D11Buffer *GetDynamicQuadBuffer() {
return quadBuffer_;
-245
View File
@@ -1,245 +0,0 @@
// Copyright (c) 2014- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <d3d11.h>
#include "Common/GPU/thin3d.h"
#include "Common/Log.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/D3D11/FramebufferManagerD3D11.h"
#include "GPU/D3D11/ShaderManagerD3D11.h"
#include "GPU/D3D11/TextureCacheD3D11.h"
#include "GPU/D3D11/D3D11Util.h"
struct StencilValueUB {
uint32_t u_stencilValue[4];
};
static const char *stencil_ps = R"(
SamplerState samp : register(s0);
Texture2D<float4> tex : register(t0);
cbuffer base : register(b0) {
int4 u_stencilValue;
};
struct PS_IN {
float2 v_texcoord0 : TEXCOORD0;
};
float4 main(PS_IN In) : SV_Target {
float4 index = tex.Sample(samp, In.v_texcoord0);
int indexBits = int(index.a * 255.99);
if ((indexBits & u_stencilValue.x) == 0)
discard;
return index.aaaa;
}
)";
// static const char *stencil_ps_fast;
static const char *stencil_vs = R"(
struct VS_IN {
float4 a_position : POSITION;
float2 a_texcoord0 : TEXCOORD0;
};
struct VS_OUT {
float2 v_texcoord0 : TEXCOORD0;
float4 position : SV_Position;
};
VS_OUT main(VS_IN In) {
VS_OUT Out;
Out.position = In.a_position;
Out.v_texcoord0 = In.a_texcoord0;
return Out;
}
)";
// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass.
bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
}
VirtualFramebuffer *dstBuffer = 0;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
if (vfb->fb_address == addr) {
dstBuffer = vfb;
}
}
if (!dstBuffer) {
return false;
}
int values = 0;
u8 usedBits = 0;
const u8 *src = Memory::GetPointer(addr);
if (!src) {
return false;
}
switch (dstBuffer->format) {
case GE_FORMAT_565:
// Well, this doesn't make much sense.
return false;
case GE_FORMAT_5551:
usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 2;
break;
case GE_FORMAT_4444:
usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 16;
break;
case GE_FORMAT_8888:
usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 256;
break;
case GE_FORMAT_INVALID:
// Impossible.
break;
}
if (usedBits == 0) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0. We're done.
return false;
}
// Clear stencil+alpha but not color. Only way is to draw a quad.
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF);
context_->RSSetState(stockD3D11.rasterStateNoCull);
context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0);
context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_);
context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context_->Draw(4, 0);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
return true;
}
// TODO: Helper with logging?
if (!stencilUploadPS_) {
std::string errorMessage;
stencilUploadPS_ = CreatePixelShaderD3D11(device_, stencil_ps, strlen(stencil_ps), featureLevel_);
}
if (!stencilUploadVS_) {
std::string errorMessage;
std::vector<uint8_t> byteCode;
stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode, featureLevel_);
ASSERT_SUCCESS(device_->CreateInputLayout(g_QuadVertexElements, 2, byteCode.data(), byteCode.size(), &stencilUploadInputLayout_));
}
if (!stencilValueBuffer_) {
D3D11_BUFFER_DESC desc{};
desc.ByteWidth = sizeof(StencilValueUB);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &stencilValueBuffer_));
}
shaderManager_->DirtyLastShader();
u16 w = dstBuffer->renderWidth;
u16 h = dstBuffer->renderHeight;
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight);
if (!tex)
return false;
if (dstBuffer->fbo) {
// Typically, STENCIL_IS_ZERO means it's already bound.
Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR;
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "Stencil");
} else {
// something is wrong...
}
D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f };
context_->RSSetViewports(1, &vp);
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
float coord[20] = {
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0,
1.0f, -1.0f, 0.0f, 1.0, 1.0,
};
D3D11_MAPPED_SUBRESOURCE map;
context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, coord, sizeof(float) * 4 * 5);
context_->Unmap(quadBuffer_, 0);
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF);
context_->IASetInputLayout(stencilUploadInputLayout_);
context_->PSSetShader(stencilUploadPS_, nullptr, 0);
context_->VSSetShader(stencilUploadVS_, nullptr, 0);
draw_->BindTextures(0, 1, &tex);
context_->RSSetState(stockD3D11.rasterStateNoCull);
context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_);
context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp);
context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF);
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
uint8_t mask = 0;
uint8_t value = 0;
if (dstBuffer->format == GE_FORMAT_4444) {
mask = i | (i << 4);
value = i * 16;
} else if (dstBuffer->format == GE_FORMAT_5551) {
mask = 0xFF;
value = i * 128;
} else {
mask = i;
value = i;
}
if (!stencilMaskStates_[mask]) {
D3D11_DEPTH_STENCIL_DESC desc{};
desc.DepthEnable = false;
desc.StencilEnable = true;
desc.StencilReadMask = 0xFF;
desc.StencilWriteMask = mask;
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE;
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
device_->CreateDepthStencilState(&desc, &stencilMaskStates_[mask]);
}
context_->OMSetDepthStencilState(stencilMaskStates_[mask], 0xFF);
D3D11_MAPPED_SUBRESOURCE map;
context_->Map(stencilValueBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
StencilValueUB ub{ (uint32_t)value };
memcpy(map.pData, &ub, sizeof(ub));
context_->Unmap(stencilValueBuffer_, 0);
context_->PSSetConstantBuffers(0, 1, &stencilValueBuffer_);
context_->Draw(4, 0);
}
tex->Release();
RebindFramebuffer("RebindFramebuffer stencil");
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
return true;
}
-2
View File
@@ -48,8 +48,6 @@ public:
void EndFrame();
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override;
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override;
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override;
-259
View File
@@ -1,259 +0,0 @@
// Copyright (c) 2014- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <d3d9.h>
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "Common/GPU/thin3d.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/TextureCacheDX9.h"
namespace DX9 {
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
static const char *stencil_ps = R"(
sampler tex: register(s0);
// TODO: Don't use fixed registers? Or don't overlap?
float4 u_stencilValue : register(c)" STR(CONST_PS_STENCILVALUE) R"();
struct PS_IN {
float2 v_texcoord0 : TEXCOORD0;
};
float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }
float4 main(PS_IN In) : COLOR {
float4 index = tex2D(tex, In.v_texcoord0);
float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x);
clip(fmod(floor(shifted), 2.0) - 0.99);
return index.aaaa;
}
)";
static const char *stencil_vs = R"(
struct VS_IN {
float4 a_position : POSITION;
float2 a_texcoord0 : TEXCOORD0;
};
struct VS_OUT {
float4 position : POSITION;
float2 v_texcoord0 : TEXCOORD0;
};
VS_OUT main(VS_IN In) {
VS_OUT Out;
Out.position = In.a_position;
Out.v_texcoord0 = In.a_texcoord0;
return Out;
}
)";
bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
}
VirtualFramebuffer *dstBuffer = 0;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
if (vfb->fb_address == addr) {
dstBuffer = vfb;
}
}
if (!dstBuffer) {
return false;
}
int values = 0;
u8 usedBits = 0;
const u8 *src = Memory::GetPointer(addr);
if (!src) {
return false;
}
switch (dstBuffer->format) {
case GE_FORMAT_565:
// Well, this doesn't make much sense.
return false;
case GE_FORMAT_5551:
usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 2;
break;
case GE_FORMAT_4444:
usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 16;
break;
case GE_FORMAT_8888:
usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 256;
break;
case GE_FORMAT_INVALID:
// Impossible.
break;
}
if (usedBits == 0) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0. We're done.
return false;
}
// Let's not bother with the shader if it's just zero.
dxstate.scissorTest.disable();
dxstate.colorMask.set(0x8);
// TODO: Verify this clears only stencil/alpha.
device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
return true;
}
if (stencilUploadFailed_) {
return false;
}
// TODO: Helper with logging?
if (!stencilUploadPS_) {
std::string errorMessage;
bool success = CompilePixelShaderD3D9(device_, stencil_ps, &stencilUploadPS_, &errorMessage);
if (!errorMessage.empty()) {
if (success) {
ERROR_LOG(G3D, "Warnings in shader compilation!");
} else {
ERROR_LOG(G3D, "Error in shader compilation!");
}
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
ERROR_LOG(G3D, "Shader source:\n%s", stencil_ps);
OutputDebugStringUTF8("Messages:\n");
OutputDebugStringUTF8(errorMessage.c_str());
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_ps);
}
if (!success) {
if (stencilUploadPS_) {
stencilUploadPS_->Release();
}
stencilUploadPS_ = nullptr;
}
}
if (!stencilUploadVS_) {
std::string errorMessage;
bool success = CompileVertexShaderD3D9(device_, stencil_vs, &stencilUploadVS_, &errorMessage);
if (!errorMessage.empty()) {
if (success) {
ERROR_LOG(G3D, "Warnings in shader compilation!");
} else {
ERROR_LOG(G3D, "Error in shader compilation!");
}
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
ERROR_LOG(G3D, "Shader source:\n%s", stencil_vs);
OutputDebugStringUTF8("Messages:\n");
OutputDebugStringUTF8(errorMessage.c_str());
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_vs);
}
if (!success) {
if (stencilUploadVS_) {
stencilUploadVS_->Release();
}
stencilUploadVS_ = nullptr;
}
}
if (!stencilUploadPS_ || !stencilUploadVS_) {
stencilUploadFailed_ = true;
return false;
}
shaderManager_->DirtyLastShader();
dxstate.colorMask.set(0x8);
dxstate.stencilTest.enable();
dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE);
u16 w = dstBuffer->renderWidth;
u16 h = dstBuffer->renderHeight;
if (dstBuffer->fbo) {
// Typically, STENCIL_IS_ZERO means it's already bound.
Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR;
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "StencilUpload");
}
D3DVIEWPORT9 vp{ 0, 0, w, h, 0.0f, 1.0f };
device_->SetViewport(&vp);
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight);
if (!tex)
return false;
// TODO: Ideally, we should clear alpha to zero here (but not RGB.)
dxstate.stencilFunc.set(D3DCMP_ALWAYS);
dxstate.stencilRef.set(0xFF);
dxstate.stencilCompareMask.set(0xFF);
float coord[20] = {
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
};
device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device_->SetVertexDeclaration(pFramebufferVertexDecl);
device_->SetPixelShader(stencilUploadPS_);
device_->SetVertexShader(stencilUploadVS_);
draw_->BindTextures(0, 1, &tex);
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
if (dstBuffer->format == GE_FORMAT_4444) {
dxstate.stencilWriteMask.set(i | (i << 4));
const float f[4] = {i * (16.0f / 255.0f)};
device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1);
} else if (dstBuffer->format == GE_FORMAT_5551) {
dxstate.stencilWriteMask.set(0xFF);
const float f[4] = {i * (128.0f / 255.0f)};
device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1);
} else {
dxstate.stencilWriteMask.set(i);
const float f[4] = {i * (1.0f / 255.0f)};
device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1);
}
HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coord, 5 * sizeof(float));
if (FAILED(hr)) {
ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, (uint32_t)hr);
}
}
tex->Release();
dxstate.stencilWriteMask.set(0xFF);
dxstate.viewport.restore();
RebindFramebuffer("RebindFramebuffer stencil");
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
return true;
}
} // namespace DX9
-10
View File
@@ -40,16 +40,6 @@ struct TransformedVertex;
struct DecVtxFormat;
enum {
TEX_SLOT_PSP_TEXTURE = 0,
TEX_SLOT_SHADERBLEND_SRC = 1,
TEX_SLOT_ALPHATEST = 2,
TEX_SLOT_CLUT = 3,
TEX_SLOT_SPLINE_POINTS = 4,
TEX_SLOT_SPLINE_WEIGHTS_U = 5,
TEX_SLOT_SPLINE_WEIGHTS_V = 6,
};
class TessellationDataTransferGLES : public TessellationDataTransfer {
private:
GLRTexture *data_tex[3]{};
+5 -3
View File
@@ -144,10 +144,12 @@ void FramebufferManagerGLES::DestroyDeviceObjects() {
render_->DeleteProgram(draw2dprogram_);
draw2dprogram_ = nullptr;
}
if (stencilUploadProgram_) {
render_->DeleteProgram(stencilUploadProgram_);
stencilUploadProgram_ = nullptr;
if (stencilUploadPipeline_) {
stencilUploadPipeline_->Release();
stencilUploadPipeline_ = nullptr;
}
if (depthDownloadProgram_) {
render_->DeleteProgram(depthDownloadProgram_);
depthDownloadProgram_ = nullptr;
-6
View File
@@ -50,8 +50,6 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
protected:
@@ -76,10 +74,6 @@ private:
GLRProgram *draw2dprogram_ = nullptr;
GLRProgram *stencilUploadProgram_ = nullptr;
int u_stencilUploadTex = -1;
int u_stencilValue = -1;
GLRProgram *depthDownloadProgram_ = nullptr;
int u_depthDownloadTex = -1;
int u_depthDownloadFactor = -1;
+1 -10
View File
@@ -513,7 +513,6 @@
<ClCompile Include="D3D11\GPU_D3D11.cpp" />
<ClCompile Include="D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="Debugger\Breakpoints.cpp" />
<ClCompile Include="Debugger\Debugger.cpp" />
@@ -525,7 +524,6 @@
<ClCompile Include="Directx9\GPU_DX9.cpp" />
<ClCompile Include="Directx9\ShaderManagerDX9.cpp" />
<ClCompile Include="Directx9\StateMappingDX9.cpp" />
<ClCompile Include="Directx9\StencilBufferDX9.cpp" />
<ClCompile Include="Directx9\TextureCacheDX9.cpp" />
<ClCompile Include="Directx9\DrawEngineDX9.cpp" />
<ClCompile Include="GeDisasm.cpp" />
@@ -572,12 +570,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GLES\StencilBufferGLES.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GLES\TextureCacheGLES.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
@@ -616,7 +608,6 @@
<ClCompile Include="Vulkan\PipelineManagerVulkan.cpp" />
<ClCompile Include="Vulkan\ShaderManagerVulkan.cpp" />
<ClCompile Include="Vulkan\StateMappingVulkan.cpp" />
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp" />
<ClCompile Include="Vulkan\TextureCacheVulkan.cpp" />
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
</ItemGroup>
@@ -675,4 +666,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+1 -13
View File
@@ -356,9 +356,6 @@
<ClCompile Include="Common\SplineCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Directx9\StencilBufferDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Common\DepalettizeShaderCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -416,9 +413,6 @@
<ClCompile Include="GLES\StateMappingGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="GLES\StencilBufferGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="GLES\DepalettizeShaderGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
@@ -455,9 +449,6 @@
<ClCompile Include="D3D11\D3D11Util.cpp">
<Filter>D3D11</Filter>
</ClCompile>
<ClCompile Include="D3D11\StencilBufferD3D11.cpp">
<Filter>D3D11</Filter>
</ClCompile>
<ClCompile Include="Common\ShaderCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -473,9 +464,6 @@
<ClCompile Include="Debugger\Record.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Vulkan\StencilBufferVulkan.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Common\StencilCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
@@ -547,4 +535,4 @@
<Filter>Shaders</Filter>
</None>
</ItemGroup>
</Project>
</Project>
+1 -1
View File
@@ -2933,7 +2933,7 @@ void GPUCommon::NotifyVideoUpload(u32 addr, int size, int width, int format) {
bool GPUCommon::PerformStencilUpload(u32 dest, int size) {
if (framebufferManager_->MayIntersectFramebuffer(dest)) {
framebufferManager_->NotifyStencilUpload(dest, size);
framebufferManager_->PerformStencilUpload(dest, size);
return true;
}
return false;
-2
View File
@@ -52,8 +52,6 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
// If within a render pass, this will just issue a regular clear. If beginning a new render pass,
// do that.
void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth);
-229
View File
@@ -1,229 +0,0 @@
// Copyright (c) 2014- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/GPU/thin3d.h"
#include "Common/GPU/Vulkan/VulkanRenderManager.h"
#include "Common/Log.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Vulkan/FramebufferManagerVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
// This shader references gl_FragDepth to prevent early fragment tests.
// They shouldn't happen since it uses discard, but Adreno detects that incorrectly - see #10634.
// This only affected the 5xx generation and was fixed sometime before driver version 512.384.0.0 (whatever that means).
// Strangely, this same code appears to fix a different issue on Exynos instead so now it's enabled on Mali as well.
static const char *stencil_fs_adreno = R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#extension GL_ARB_conservative_depth : enable
layout (depth_unchanged) out float gl_FragDepth;
layout (binding = 0) uniform sampler2D tex;
layout (push_constant) uniform params {
int u_stencilValue;
};
layout (location = 0) in vec2 v_texcoord0;
layout (location = 0) out vec4 fragColor0;
void main() {
gl_FragDepth = gl_FragCoord.z;
if (u_stencilValue == 0) {
fragColor0 = vec4(0.0);
} else {
vec4 index = texture(tex, v_texcoord0);
int indexBits = int(floor(index.a * 255.99)) & 0xFF;
if ((indexBits & u_stencilValue) == 0)
discard;
fragColor0 = index.aaaa;
}
}
)";
static const char *stencil_fs = R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 0) uniform sampler2D tex;
layout (push_constant) uniform params {
int u_stencilValue;
};
layout (location = 0) in vec2 v_texcoord0;
layout (location = 0) out vec4 fragColor0;
void main() {
if (u_stencilValue == 0) {
fragColor0 = vec4(0.0);
} else {
vec4 index = texture(tex, v_texcoord0);
int indexBits = int(floor(index.a * 255.99)) & 0xFF;
if ((indexBits & u_stencilValue) == 0)
discard;
fragColor0 = index.aaaa;
}
}
)";
static const char stencil_vs[] = R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) out vec2 v_texcoord0;
out gl_PerVertex { vec4 gl_Position; };
void main() {
int id = gl_VertexIndex;
v_texcoord0.x = (id == 2) ? 2.0 : 0.0;
v_texcoord0.y = (id == 1) ? 2.0 : 0.0;
gl_Position = vec4(v_texcoord0 * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0);
}
)";
// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without
// messing about with bitplane textures and the like. Or actually, maybe not... Let's start with
// the traditional approach.
bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
}
VirtualFramebuffer *dstBuffer = 0;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
if (vfb->fb_address == addr) {
dstBuffer = vfb;
}
}
if (!dstBuffer) {
return false;
}
int values = 0;
u8 usedBits = 0;
const u8 *src = Memory::GetPointer(addr);
if (!src) {
return false;
}
switch (dstBuffer->format) {
case GE_FORMAT_565:
// Well, this doesn't make much sense.
return false;
case GE_FORMAT_5551:
usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 2;
break;
case GE_FORMAT_4444:
usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 16;
break;
case GE_FORMAT_8888:
usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight);
values = 256;
break;
case GE_FORMAT_INVALID:
case GE_FORMAT_DEPTH16:
// Inconceivable.
_assert_(false);
break;
}
std::string error;
if (!stencilVs_) {
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
const char *stencil_fs_source = stencil_fs;
// See comment above the stencil_fs_adreno definition.
u32 vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID;
if (g_Config.bVendorBugChecksEnabled && (draw_->GetBugs().Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL) || vendorID == VULKAN_VENDOR_ARM))
stencil_fs_source = stencil_fs_adreno;
stencilVs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error);
stencilFs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, stencil_fs_source, &error);
}
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
shaderManager_->DirtyLastShader();
textureCache_->ForgetLastTexture();
u16 w = dstBuffer->renderWidth;
u16 h = dstBuffer->renderHeight;
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight);
if (!tex)
return false;
if (dstBuffer->fbo) {
// Typically, STENCIL_IS_ZERO means it's already bound, so this bind will be optimized away.
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "Stencil");
} else {
// something is wrong...
}
VkPipeline pipeline = vulkan2D_->GetPipeline(rp, stencilVs_, stencilFs_, false, Vulkan2D::VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS);
renderManager->BindPipeline(pipeline, PIPELINE_FLAG_USES_DEPTH_STENCIL);
renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f });
renderManager->SetScissor(0, 0, (int)w, (int)h);
draw_->BindTextures(0, 1, &tex);
VkImageView drawPixelsImageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(drawPixelsImageView, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
// Note: Even with skipZero, we don't necessarily start framebuffers at 0 in Vulkan. Clear anyway.
// Not an actual clear, because we need to draw to alpha only as well.
uint32_t value = 0;
renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value);
renderManager->SetStencilParams(0xFF, 0xFF, 0x00);
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
// These are the stencil bits that will be written. We discard when the bit doesn't match.
uint8_t writeMask = 0;
// This is the value to test the texture alpha against in the shader.
uint32_t value = 0;
if (dstBuffer->format == GE_FORMAT_4444) {
writeMask = i | (i << 4);
value = i * 16;
} else if (dstBuffer->format == GE_FORMAT_5551) {
writeMask = 0xFF;
value = i * 128;
} else {
writeMask = i;
value = i;
}
renderManager->SetStencilParams(writeMask, 0xFF, 0xFF);
// Need to specify both VERTEX and FRAGMENT bits here since that's what we set up in the pipeline layout, and we need
// that for the post shaders. There's probably not really a cost to this.
renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value);
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle
}
tex->Release();
RebindFramebuffer("RebindFramebuffer - NotifyStencilUpload");
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
return true;
}
-1
View File
@@ -470,7 +470,6 @@
<ClCompile Include="..\..\GPU\D3D11\GPU_D3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp" />
-1
View File
@@ -30,7 +30,6 @@
<ClCompile Include="..\..\GPU\D3D11\GPU_D3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\ShaderManagerD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StateMappingD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\StencilBufferD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\TextureCacheD3D11.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp" />
-2
View File
@@ -133,7 +133,6 @@ VULKAN_FILES := \
$(SRC)/GPU/Vulkan/PipelineManagerVulkan.cpp \
$(SRC)/GPU/Vulkan/ShaderManagerVulkan.cpp \
$(SRC)/GPU/Vulkan/StateMappingVulkan.cpp \
$(SRC)/GPU/Vulkan/StencilBufferVulkan.cpp \
$(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \
$(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \
$(SRC)/GPU/Vulkan/VulkanUtil.cpp \
@@ -351,7 +350,6 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \
$(SRC)/GPU/GLES/DepthBufferGLES.cpp \
$(SRC)/GPU/GLES/GPU_GLES.cpp.arm \
$(SRC)/GPU/GLES/StencilBufferGLES.cpp \
$(SRC)/GPU/GLES/TextureCacheGLES.cpp.arm \
$(SRC)/GPU/GLES/DrawEngineGLES.cpp.arm \
$(SRC)/GPU/GLES/StateMappingGLES.cpp.arm \
-4
View File
@@ -369,7 +369,6 @@ SOURCES_CXX += \
$(GPUDIR)/GLES/TextureCacheGLES.cpp \
$(GPUDIR)/GLES/ShaderManagerGLES.cpp \
$(GPUDIR)/GLES/StateMappingGLES.cpp \
$(GPUDIR)/GLES/StencilBufferGLES.cpp \
$(EXTDIR)/glslang/OGLCompilersDLL/InitializeDll.cpp \
$(EXTDIR)/glslang/glslang/GenericCodeGen/CodeGen.cpp \
$(EXTDIR)/glslang/glslang/GenericCodeGen/Link.cpp \
@@ -732,7 +731,6 @@ SOURCES_CXX += \
$(GPUDIR)/Vulkan/PipelineManagerVulkan.cpp \
$(GPUDIR)/Vulkan/ShaderManagerVulkan.cpp \
$(GPUDIR)/Vulkan/StateMappingVulkan.cpp \
$(GPUDIR)/Vulkan/StencilBufferVulkan.cpp \
$(GPUDIR)/Vulkan/TextureCacheVulkan.cpp \
$(GPUDIR)/Vulkan/VulkanUtil.cpp \
$(LIBRETRODIR)/LibretroVulkanContext.cpp \
@@ -747,7 +745,6 @@ SOURCES_CXX += \
$(GPUDIR)/Directx9/GPU_DX9.cpp \
$(GPUDIR)/Directx9/ShaderManagerDX9.cpp \
$(GPUDIR)/Directx9/StateMappingDX9.cpp \
$(GPUDIR)/Directx9/StencilBufferDX9.cpp \
$(GPUDIR)/Directx9/TextureCacheDX9.cpp
SOURCES_CXX += \
@@ -758,7 +755,6 @@ SOURCES_CXX += \
$(GPUDIR)/D3D11/D3D11Util.cpp \
$(GPUDIR)/D3D11/ShaderManagerD3D11.cpp \
$(GPUDIR)/D3D11/StateMappingD3D11.cpp \
$(GPUDIR)/D3D11/StencilBufferD3D11.cpp \
$(GPUDIR)/D3D11/TextureCacheD3D11.cpp \
$(LIBRETRODIR)/LibretroD3D11Context.cpp
+67 -13
View File
@@ -13,6 +13,7 @@
#include "GPU/Common/FragmentShaderGenerator.h"
#include "GPU/Common/VertexShaderGenerator.h"
#include "GPU/Common/ReinterpretFramebuffer.h"
#include "GPU/Common/StencilCommon.h"
#if PPSSPP_PLATFORM(WINDOWS)
#include "GPU/D3D11/D3D11Util.h"
@@ -89,18 +90,18 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
}
}
bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std::string *errorMessage) {
bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stage, std::string *errorMessage) {
std::vector<uint32_t> spirv;
switch (lang) {
#if PPSSPP_PLATFORM(WINDOWS)
case ShaderLanguage::HLSL_D3D11:
{
auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0);
auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), stage == ShaderStage::Vertex ? "vs_4_0" : "ps_4_0", 0);
return !output.empty();
}
case ShaderLanguage::HLSL_D3D9:
{
LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, vertex ? "vs_2_0" : "ps_2_0", errorMessage);
LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, stage == ShaderStage::Vertex ? "vs_2_0" : "ps_2_0", errorMessage);
if (blob) {
blob->Release();
return true;
@@ -111,11 +112,11 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std
#endif
case ShaderLanguage::GLSL_VULKAN:
return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage);
return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage);
case ShaderLanguage::GLSL_1xx:
return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage);
return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage);
case ShaderLanguage::GLSL_3xx:
return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage);
return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage);
default:
return false;
}
@@ -159,6 +160,8 @@ const char *ShaderLanguageToString(ShaderLanguage lang) {
}
bool TestReinterpretShaders() {
Draw::Bugs bugs;
ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D11,
@@ -183,7 +186,7 @@ bool TestReinterpretShaders() {
failed = true;
} else {
std::string errorMessage;
if (!TestCompileShader(buffer, languages[k], true, &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;
@@ -197,6 +200,7 @@ bool TestReinterpretShaders() {
printf("=== %s ===\n\n", ShaderLanguageToString(languages[k]));
ShaderLanguageDesc desc(languages[k]);
std::string errorMessage;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -206,8 +210,7 @@ bool TestReinterpretShaders() {
printf("Failed!\n%s\n", buffer);
failed = true;
} else {
std::string errorMessage;
if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) {
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;
@@ -217,8 +220,55 @@ bool TestReinterpretShaders() {
}
}
}
}
delete[] buffer;
return !failed;
}
bool TestStencilShaders() {
Draw::Bugs bugs;
ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D9,
ShaderLanguage::HLSL_D3D11,
#endif
ShaderLanguage::GLSL_VULKAN,
ShaderLanguage::GLSL_3xx,
};
char *buffer = new char[65536];
bool failed = false;
for (int k = 0; k < ARRAY_SIZE(languages); k++) {
printf("=== %s ===\n\n", ShaderLanguageToString(languages[k]));
ShaderLanguageDesc desc(languages[k]);
std::string errorMessage;
// Generate all despite failures - it's only 6.
GenerateStencilFs(buffer, desc, bugs);
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling stencil 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);
}
GenerateStencilVs(buffer, desc);
if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) {
printf("Error compiling stencil 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);
}
}
delete[] buffer;
return !failed;
}
@@ -281,7 +331,7 @@ bool TestVertexShaders() {
for (int j = 0; j < numLanguages; j++) {
if (generateSuccess[j]) {
std::string errorMessage;
if (!TestCompileShader(buffer[j], languages[j], true, &errorMessage)) {
if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Vertex, &errorMessage)) {
printf("Error compiling vertex shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str());
return false;
}
@@ -343,7 +393,7 @@ bool TestFragmentShaders() {
for (int j = 0; j < numLanguages; j++) {
if (generateSuccess[j]) {
std::string errorMessage;
if (!TestCompileShader(buffer[j], languages[j], false, &errorMessage)) {
if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str());
return false;
}
@@ -369,7 +419,7 @@ bool TestShaderGenerators() {
init_glslang();
#endif
if (!TestFragmentShaders()) {
if (!TestStencilShaders()) {
return false;
}
@@ -377,6 +427,10 @@ bool TestShaderGenerators() {
return false;
}
if (!TestFragmentShaders()) {
return false;
}
if (!TestVertexShaders()) {
return false;
}