mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Add brute force shader generator tester. Tests D3D11 and Vulkan shaders.
Found a potential error with tesselation without normals already.
This commit is contained in:
parent
712f56fb7d
commit
c6f51bbc1e
@ -19,7 +19,7 @@
|
||||
|
||||
#include "D3D11Util.h"
|
||||
|
||||
static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t codeSize, const char *target, UINT flags) {
|
||||
std::vector<uint8_t> CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags) {
|
||||
ID3DBlob *compiledCode = nullptr;
|
||||
ID3DBlob *errorMsgs = nullptr;
|
||||
HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs);
|
||||
@ -31,8 +31,10 @@ static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t cod
|
||||
errorMsgs->Release();
|
||||
}
|
||||
if (compiledCode) {
|
||||
// Success!
|
||||
const uint8_t *buf = (const uint8_t *)compiledCode->GetBufferPointer();
|
||||
std::vector<uint8_t> compiled = std::vector<uint8_t>(buf, buf + compiledCode->GetBufferSize());
|
||||
_assert_(compiled.size() != 0);
|
||||
compiledCode->Release();
|
||||
return compiled;
|
||||
}
|
||||
@ -41,7 +43,7 @@ static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t cod
|
||||
|
||||
ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags) {
|
||||
const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "vs_4_0_level_9_1" : "vs_4_0";
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, profile, flags);
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags);
|
||||
if (byteCode.empty())
|
||||
return nullptr;
|
||||
|
||||
@ -54,7 +56,7 @@ ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *co
|
||||
|
||||
ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) {
|
||||
const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "ps_4_0_level_9_1" : "ps_4_0";
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, profile, flags);
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags);
|
||||
if (byteCode.empty())
|
||||
return nullptr;
|
||||
|
||||
@ -66,7 +68,7 @@ ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code
|
||||
ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) {
|
||||
if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
|
||||
return nullptr;
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "cs_4_0", flags);
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "cs_4_0", flags);
|
||||
if (byteCode.empty())
|
||||
return nullptr;
|
||||
|
||||
@ -78,7 +80,7 @@ ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *
|
||||
ID3D11GeometryShader *CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) {
|
||||
if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
|
||||
return nullptr;
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "gs_5_0", flags);
|
||||
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "gs_5_0", flags);
|
||||
if (byteCode.empty())
|
||||
return nullptr;
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
class PushBufferD3D11 {
|
||||
@ -71,6 +73,8 @@ private:
|
||||
bool nextMapDiscard_ = false;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags);
|
||||
|
||||
ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0);
|
||||
ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0);
|
||||
ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0);
|
||||
@ -95,4 +99,4 @@ public:
|
||||
if (!SUCCEEDED((x))) \
|
||||
Crash();
|
||||
|
||||
extern StockObjectsD3D11 stockD3D11;
|
||||
extern StockObjectsD3D11 stockD3D11;
|
||||
|
@ -19,6 +19,6 @@
|
||||
#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h"
|
||||
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
|
||||
|
||||
void GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang) {
|
||||
DX9::GenerateFragmentShaderHLSL(id, buffer, lang);
|
||||
bool GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang) {
|
||||
return DX9::GenerateFragmentShaderHLSL(id, buffer, lang);
|
||||
}
|
||||
|
@ -19,4 +19,4 @@
|
||||
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
|
||||
void GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang);
|
||||
bool GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang);
|
||||
|
@ -19,6 +19,6 @@
|
||||
#include "GPU/D3D11/VertexShaderGeneratorD3D11.h"
|
||||
#include "GPU/Directx9/VertexShaderGeneratorDX9.h"
|
||||
|
||||
void GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang) {
|
||||
DX9::GenerateVertexShaderHLSL(id, buffer, lang);
|
||||
bool GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang) {
|
||||
return DX9::GenerateVertexShaderHLSL(id, buffer, lang);
|
||||
}
|
||||
|
@ -19,4 +19,4 @@
|
||||
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
|
||||
void GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang);
|
||||
bool GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang);
|
||||
|
@ -587,7 +587,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
|
||||
VSShader *vs;
|
||||
if (vsIter == vsCache_.end()) {
|
||||
// Vertex shader not in cache. Let's compile it.
|
||||
GenerateVertexShaderHLSL(VSID, codeBuffer_);
|
||||
GenerateVertexShaderHLSL(VSID, codeBuffer_, HLSL_DX9);
|
||||
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
|
||||
|
||||
if (vs->Failed()) {
|
||||
@ -605,7 +605,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
|
||||
// next time and we'll do this over and over...
|
||||
|
||||
// Can still work with software transform.
|
||||
GenerateVertexShaderHLSL(VSID, codeBuffer_);
|
||||
GenerateVertexShaderHLSL(VSID, codeBuffer_, HLSL_DX9);
|
||||
vs = new VSShader(device_, VSID, codeBuffer_, false);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang = HLSL_DX9);
|
||||
bool GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang);
|
||||
|
||||
enum {
|
||||
CONST_VS_PROJ = 0,
|
||||
|
174
unittest/TestShaderGenerators.cpp
Normal file
174
unittest/TestShaderGenerators.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "Common/Data/Random/Rng.h"
|
||||
|
||||
#include "GPU/Vulkan/VulkanContext.h"
|
||||
|
||||
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
||||
#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h"
|
||||
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
|
||||
#include "GPU/GLES/FragmentShaderGeneratorGLES.h"
|
||||
|
||||
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
||||
#include "GPU/D3D11/VertexShaderGeneratorD3D11.h"
|
||||
#include "GPU/Directx9/VertexShaderGeneratorDX9.h"
|
||||
#include "GPU/GLES/VertexShaderGeneratorGLES.h"
|
||||
|
||||
#include "GPU/D3D11/D3D11Util.h"
|
||||
#include "GPU/D3D11/D3D11Loader.h"
|
||||
|
||||
#include "GPU/D3D9/D3DCompilerLoader.h"
|
||||
#include "GPU/D3D9/D3D9ShaderCompiler.h"
|
||||
|
||||
bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang) {
|
||||
switch (lang) {
|
||||
case ShaderLanguage::HLSL_D3D11:
|
||||
return GenerateFragmentShaderD3D11(id, buffer, ShaderLanguage::HLSL_D3D11);
|
||||
case ShaderLanguage::HLSL_DX9:
|
||||
DX9::GenerateFragmentShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9);
|
||||
// TODO: Need a device :( Returning false here so it doesn't get tried.
|
||||
return false;
|
||||
case ShaderLanguage::GLSL_VULKAN:
|
||||
return GenerateVulkanGLSLFragmentShader(id, buffer, 0);
|
||||
case ShaderLanguage::GLSL_140:
|
||||
case ShaderLanguage::GLSL_300:
|
||||
// TODO: Need a device - except that maybe glslang could be used to verify these ....
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang) {
|
||||
switch (lang) {
|
||||
case ShaderLanguage::HLSL_D3D11:
|
||||
return GenerateVertexShaderD3D11(id, buffer, ShaderLanguage::HLSL_D3D11);
|
||||
case ShaderLanguage::HLSL_DX9:
|
||||
DX9::GenerateVertexShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9);
|
||||
// TODO: Need a device :( Returning false here so it doesn't get tried.
|
||||
return false;
|
||||
// return DX9::GenerateFragmentShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9);
|
||||
case ShaderLanguage::GLSL_VULKAN:
|
||||
return GenerateVulkanGLSLVertexShader(id, buffer);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex) {
|
||||
switch (lang) {
|
||||
case ShaderLanguage::HLSL_D3D11:
|
||||
{
|
||||
auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0);
|
||||
return !output.empty();
|
||||
}
|
||||
case ShaderLanguage::HLSL_DX9:
|
||||
return false;
|
||||
case ShaderLanguage::GLSL_VULKAN:
|
||||
{
|
||||
std::vector<uint32_t> spirv;
|
||||
std::string errorMessage;
|
||||
bool result = GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, spirv, &errorMessage);
|
||||
if (!result) {
|
||||
printf("GLSLtoSPV ERROR:\n%s\n\n", errorMessage.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case ShaderLanguage::GLSL_140:
|
||||
|
||||
return false;
|
||||
case ShaderLanguage::GLSL_300:
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestShaderGenerators() {
|
||||
LoadD3D11();
|
||||
init_glslang();
|
||||
LoadD3DCompilerDynamic();
|
||||
|
||||
ShaderLanguage languages[] = {
|
||||
ShaderLanguage::HLSL_D3D11,
|
||||
ShaderLanguage::GLSL_VULKAN,
|
||||
ShaderLanguage::GLSL_140,
|
||||
ShaderLanguage::GLSL_300,
|
||||
ShaderLanguage::HLSL_DX9,
|
||||
};
|
||||
const int numLanguages = ARRAY_SIZE(languages);
|
||||
|
||||
char *buffer[numLanguages];
|
||||
|
||||
for (int i = 0; i < numLanguages; i++) {
|
||||
buffer[i] = new char[65536];
|
||||
}
|
||||
// Generate a bunch of random fragment shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
GMRng rng;
|
||||
int successes = 0;
|
||||
int count = 200;
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
FShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
|
||||
bool generateSuccess[numLanguages]{};
|
||||
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j]);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
if (generateSuccess[j]) {
|
||||
if (!TestCompileShader(buffer[j], languages[j], false)) {
|
||||
printf("Error compiling fragment shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str());
|
||||
return false;
|
||||
}
|
||||
successes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d/%d fragment shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages);
|
||||
|
||||
// Now try vertex shaders.
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
VShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
|
||||
bool generateSuccess[numLanguages]{};
|
||||
|
||||
for (int j = 0; j < numLanguages; j++) {
|
||||
generateSuccess[j] = GenerateVShader(id, buffer[j], languages[j]);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
if (generateSuccess[j]) {
|
||||
if (!TestCompileShader(buffer[j], languages[j], true)) {
|
||||
printf("Error compiling vertex shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str());
|
||||
return false;
|
||||
}
|
||||
successes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numLanguages; i++) {
|
||||
delete[] buffer[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -571,6 +571,7 @@ struct TestItem {
|
||||
bool TestArmEmitter();
|
||||
bool TestArm64Emitter();
|
||||
bool TestX64Emitter();
|
||||
bool TestShaderGenerators();
|
||||
|
||||
TestItem availableTests[] = {
|
||||
#if PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
|
||||
@ -593,7 +594,7 @@ TestItem availableTests[] = {
|
||||
TEST_ITEM(ParseLBN),
|
||||
TEST_ITEM(QuickTexHash),
|
||||
TEST_ITEM(CLZ),
|
||||
TEST_ITEM(MemMap),
|
||||
TEST_ITEM(ShaderGenerators),
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
@ -382,6 +382,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestShaderGenerators.cpp" />
|
||||
<ClCompile Include="TestVertexJit.cpp" />
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
<ClCompile Include="TestArmEmitter.cpp">
|
||||
@ -426,4 +427,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -11,6 +11,7 @@
|
||||
<ClCompile Include="..\Windows\CaptureDevice.cpp">
|
||||
<Filter>Windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestShaderGenerators.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="JitHarness.h" />
|
||||
|
Loading…
Reference in New Issue
Block a user