mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Merge pull request #15754 from hrydgard/unify-stencil-draw
Unify stencil upload using thin3d
This commit is contained in:
36 files changed
+459
-864
No files matched your search
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
struct InputDef {
|
||||
const char *type;
|
||||
const char *name;
|
||||
const char *semantic;
|
||||
};
|
||||
|
||||
struct UniformDef {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,6 @@ private:
|
||||
std::vector<float> alphaStack_;
|
||||
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
Draw::Buffer *vbuf_ = nullptr;
|
||||
Draw::Pipeline *pipeline_ = nullptr;
|
||||
|
||||
Vertex *verts_;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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]{};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user