GPU: Verify generated shader buffer length.

Hardware tessellation + uberlighting + clamp was exceeding the buffer,
causing memory corruption.  Let's try to catch it, but also increase
buffers to be safe.
This commit is contained in:
Unknown W. Brackets 2022-10-05 21:41:09 -07:00
parent 1469a32a9d
commit aee2ad46a2
7 changed files with 90 additions and 18 deletions

View File

@ -178,9 +178,10 @@ void Draw2D::Ensure2DResources() {
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
if (!draw2DVs_) {
char *vsCode = new char[4000];
char *vsCode = new char[8192];
ShaderWriter writer(vsCode, shaderLanguageDesc, ShaderStage::Vertex);
GenerateDraw2DVS(writer);
_assert_msg_(strlen(vsCode) < 8192, "Draw2D VS length error: %d", (int)strlen(vsCode));
draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs");
_assert_(draw2DVs_);
delete[] vsCode;
@ -215,9 +216,10 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade
using namespace Draw;
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
char *fsCode = new char[4000];
char *fsCode = new char[8192];
ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment);
Draw2DPipelineInfo info = generate(writer);
_assert_msg_(strlen(fsCode) < 8192, "Draw2D FS length error: %d", (int)strlen(fsCode));
ShaderModule *fs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), info.tag);

View File

@ -199,11 +199,14 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU
if (!stencilUploadPipeline_) {
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
char *fsCode = new char[4000];
char *vsCode = new char[4000];
char *fsCode = new char[8192];
char *vsCode = new char[8192];
GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs());
GenerateStencilVs(vsCode, shaderLanguageDesc);
_assert_msg_(strlen(fsCode) < 8192, "StenFS length error: %d", (int)strlen(fsCode));
_assert_msg_(strlen(vsCode) < 8192, "StenVS length error: %d", (int)strlen(vsCode));
ShaderModule *stencilUploadFs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs");
ShaderModule *stencilUploadVs = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs");

View File

@ -209,7 +209,6 @@ Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETe
config.smoothedDepal = smoothedDepal;
config.depthUpperBits = depthUpperBits;
char *buffer = new char[4096];
Draw2DPipeline *ts = draw2D_->Create2DPipeline([=](ShaderWriter &writer) -> Draw2DPipelineInfo {
GenerateDepalFs(writer, config);
return Draw2DPipelineInfo{
@ -219,7 +218,6 @@ Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETe
samplers
};
});
delete[] buffer;
depalCache_[id] = ts;

View File

@ -88,9 +88,11 @@ std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const
}
}
static constexpr size_t CODE_BUFFER_SIZE = 32768;
ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel)
: ShaderManagerCommon(draw), device_(device), context_(context), featureLevel_(featureLevel) {
codeBuffer_ = new char[16384];
codeBuffer_ = new char[CODE_BUFFER_SIZE];
memset(&ub_base, 0, sizeof(ub_base));
memset(&ub_lights, 0, sizeof(ub_lights));
memset(&ub_bones, 0, sizeof(ub_bones));
@ -211,6 +213,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
uint32_t attrMask;
uint64_t uniformMask;
GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString);
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform);
vsCache_[VSID] = vs;
} else {
@ -225,6 +228,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
std::string genErrorString;
uint64_t uniformMask;
GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, nullptr, &genErrorString);
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform);
fsCache_[FSID] = fs;
} else {

View File

@ -662,10 +662,12 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
}
}
static constexpr size_t CODE_BUFFER_SIZE = 32768;
ShaderManagerGLES::ShaderManagerGLES(Draw::DrawContext *draw)
: ShaderManagerCommon(draw), fsCache_(16), vsCache_(16) {
render_ = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
codeBuffer_ = new char[16384];
codeBuffer_ = new char[CODE_BUFFER_SIZE];
lastFSID_.set_invalid();
lastVSID_.set_invalid();
}
@ -728,6 +730,7 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) {
ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str());
return nullptr;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
std::string desc = FragmentShaderDesc(FSID);
ShaderDescGLES params{ GL_FRAGMENT_SHADER, 0, uniformMask };
return new Shader(render_, codeBuffer_, desc, params);
@ -742,6 +745,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str());
return nullptr;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
std::string desc = VertexShaderDesc(VSID);
ShaderDescGLES params{ GL_VERTEX_SHADER, attrMask, uniformMask };
params.useHWTransform = useHWTransform;

View File

@ -194,9 +194,11 @@ std::string VulkanGeometryShader::GetShaderString(DebugShaderStringType type) co
}
}
static constexpr size_t CODE_BUFFER_SIZE = 32768;
ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw)
: ShaderManagerCommon(draw), compat_(GLSL_VULKAN), fsCache_(16), vsCache_(16), gsCache_(16) {
codeBuffer_ = new char[16384];
codeBuffer_ = new char[CODE_BUFFER_SIZE];
VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
uboAlignment_ = vulkan->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment;
memset(&ub_base, 0, sizeof(ub_base));
@ -330,6 +332,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
uint32_t attributeMask = 0; // Not used
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString);
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new VulkanVertexShader(vulkan, VSID, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
@ -342,6 +345,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
FragmentShaderFlags flags;
bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
}
@ -354,6 +358,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
std::string genErrorString;
bool success = GenerateGeometryShader(GSID, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString);
_assert_msg_(success, "GS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
@ -512,6 +517,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString)) {
return false;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, codeBuffer_, useHWTransform);
vsCache_.Insert(id, vs);
}
@ -529,6 +535,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) {
return false;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan, id, flags, codeBuffer_);
fsCache_.Insert(id, fs);
}
@ -543,6 +550,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
return false;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
}

View File

@ -25,6 +25,8 @@
#include "GPU/D3D9/D3D9ShaderCompiler.h"
#endif
static constexpr size_t CODE_BUFFER_SIZE = 32768;
bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) {
uint64_t uniformMask;
switch (lang) {
@ -243,10 +245,13 @@ bool TestReinterpretShaders() {
continue; // useless shader!
ShaderWriter writer(buffer, desc, ShaderStage::Fragment, nullptr, 0);
GenerateReinterpretFragmentShader(writer, fmts[i], fmts[j]);
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());
if (strlen(buffer) >= 8192) {
printf("Reinterpret fragment shader %d exceeded buffer:\n\n%s\n", (int)j, LineNumberString(buffer).c_str());
failed = true;
}
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling reinterpret fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
return false;
} else {
printf("===\n%s\n===\n", buffer);
}
@ -282,19 +287,25 @@ bool TestStencilShaders() {
// Generate all despite failures - it's only 6.
GenerateStencilFs(buffer, desc, bugs);
if (strlen(buffer) >= 8192) {
printf("Stencil fragment shader exceeded buffer:\n\n%s\n", LineNumberString(buffer).c_str());
failed = true;
}
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 (strlen(buffer) >= 8192) {
printf("Stencil vertex shader exceeded buffer:\n\n%s\n", LineNumberString(buffer).c_str());
failed = true;
}
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);
}
@ -319,8 +330,6 @@ bool TestDepalShaders() {
char *buffer = new char[65536];
bool failed = false;
for (int k = 0; k < ARRAY_SIZE(languages); k++) {
printf("=== %s ===\n\n", ShaderLanguageToString(languages[k]));
@ -340,9 +349,14 @@ bool TestDepalShaders() {
ShaderWriter writer(buffer, desc, ShaderStage::Fragment);
GenerateDepalFs(writer, config);
if (strlen(buffer) >= 8192) {
printf("Depal shader exceeded buffer:\n\n%s\n", LineNumberString(buffer).c_str());
delete[] buffer;
return false;
}
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
printf("Error compiling depal shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str());
failed = true;
delete[] buffer;
return false;
} else {
printf("===\n%s\n===\n", buffer);
@ -350,7 +364,7 @@ bool TestDepalShaders() {
}
delete[] buffer;
return !failed;
return true;
}
const ShaderLanguage languages[] = {
@ -410,6 +424,16 @@ bool TestVertexShaders() {
}
}
for (int j = 0; j < numLanguages; j++) {
if (strlen(buffer[j]) >= CODE_BUFFER_SIZE) {
printf("Vertex shader exceeded buffer:\n\n%s\n", LineNumberString(buffer[j]).c_str());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
}
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
// let's try to compile them.
for (int j = 0; j < numLanguages; j++) {
@ -417,6 +441,9 @@ bool TestVertexShaders() {
std::string 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());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
successes++;
@ -471,6 +498,16 @@ bool TestFragmentShaders() {
// We ignore the contents of the error string here, not even gonna try to compile if it errors.
}
for (int j = 0; j < numLanguages; j++) {
if (strlen(buffer[j]) >= CODE_BUFFER_SIZE) {
printf("Fragment shader exceeded buffer:\n\n%s\n", LineNumberString(buffer[j]).c_str());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
}
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
// let's try to compile them.
for (int j = 0; j < numLanguages; j++) {
@ -478,6 +515,9 @@ bool TestFragmentShaders() {
std::string 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());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
successes++;
@ -527,6 +567,16 @@ bool TestGeometryShaders() {
// We ignore the contents of the error string here, not even gonna try to compile if it errors.
}
for (int j = 0; j < numLanguages; j++) {
if (strlen(buffer[j]) >= CODE_BUFFER_SIZE) {
printf("Geoemtry shader exceeded buffer:\n\n%s\n", LineNumberString(buffer[j]).c_str());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
}
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
// let's try to compile them.
for (int j = 0; j < numLanguages; j++) {
@ -534,6 +584,9 @@ bool TestGeometryShaders() {
std::string errorMessage;
if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Geometry, &errorMessage)) {
printf("Error compiling geometry shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
successes++;