mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-07 21:23:29 +02:00
The shader creation helpers returned S_FALSE when compilation produced no bytecode - but S_FALSE is a success code, so the FAILED() checks in the D3D11VertexShader/D3D11FragmentShader constructors never fired and failed_ was never set. Return E_FAIL instead, and only hand out the bytecode when the shader object was actually created. Failed() had no callers at all, so a failed shader was handed to the draw as usual: VSSetShader(nullptr), CreateInputLayout on empty bytecode, and the ignored HRESULT from SetupDecFmtForDraw meant IASetInputLayout(nullptr). The draw then did nothing, with no log line to explain it. Skip the draw and warn instead, like the GL backend does.
116 lines
4.1 KiB
C++
116 lines
4.1 KiB
C++
#include "ppsspp_config.h"
|
|
|
|
#include <cstdint>
|
|
#include <cfloat>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <d3d11.h>
|
|
#include <D3Dcompiler.h>
|
|
|
|
#if PPSSPP_PLATFORM(UWP)
|
|
#define ptr_D3DCompile D3DCompile
|
|
#else
|
|
#include "Common/GPU/D3D11/D3D11Loader.h"
|
|
#endif
|
|
|
|
#include "Common/CommonFuncs.h"
|
|
#include "Common/Log.h"
|
|
#include "Common/StringUtils.h"
|
|
|
|
#include "D3D11Util.h"
|
|
#include <wrl/client.h>
|
|
|
|
using namespace Microsoft::WRL;
|
|
|
|
std::vector<uint8_t> CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags, std::string *errorMessage) {
|
|
ComPtr<ID3DBlob> compiledCode;
|
|
ComPtr<ID3DBlob> errorMsgs;
|
|
HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs);
|
|
std::string errors;
|
|
if (errorMsgs) {
|
|
errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize() > 1 ? (errorMsgs->GetBufferSize() - 1) : 0);
|
|
std::string numberedCode = LineNumberString(code);
|
|
if (SUCCEEDED(result)) {
|
|
std::vector<std::string_view> lines;
|
|
SplitString(errors, '\n', lines);
|
|
for (auto &line : lines) {
|
|
auto trimmed = StripSpaces(line);
|
|
// Ignore the useless warning about taking the power of negative numbers.
|
|
if (trimmed.find("pow(f, e) will not work for negative f") != std::string::npos) {
|
|
continue;
|
|
}
|
|
if (trimmed.size() > 1) { // ignore single nulls, not sure how they appear.
|
|
WARN_LOG(Log::G3D, "%.*s", (int)trimmed.length(), trimmed.data());
|
|
}
|
|
}
|
|
} else {
|
|
ERROR_LOG(Log::G3D, "%s: %s\n\n%s", "errors", errors.c_str(), numberedCode.c_str());
|
|
if (errorMessage) {
|
|
*errorMessage = errors;
|
|
}
|
|
OutputDebugStringA(errors.c_str());
|
|
OutputDebugStringA(numberedCode.c_str());
|
|
}
|
|
}
|
|
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);
|
|
return compiled;
|
|
}
|
|
return std::vector<uint8_t>();
|
|
}
|
|
|
|
HRESULT CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11VertexShader **ppVertexShader) {
|
|
if (ppVertexShader)
|
|
*ppVertexShader = nullptr;
|
|
const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "vs_4_0_level_9_1" : "vs_4_0";
|
|
std::string errorMessage;
|
|
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags, &errorMessage);
|
|
if (byteCode.empty()) {
|
|
if (!errorMessage.empty()) {
|
|
ERROR_LOG(Log::G3D, "%s", errorMessage.c_str());
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
auto hr = device->CreateVertexShader(byteCode.data(), byteCode.size(), nullptr, ppVertexShader);
|
|
if (SUCCEEDED(hr) && byteCodeOut)
|
|
*byteCodeOut = byteCode;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11PixelShader **ppPixelShader) {
|
|
if (ppPixelShader)
|
|
*ppPixelShader = nullptr;
|
|
const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "ps_4_0_level_9_1" : "ps_4_0";
|
|
std::string errorMessage;
|
|
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags, &errorMessage);
|
|
if (byteCode.empty()) {
|
|
if (!errorMessage.empty()) {
|
|
ERROR_LOG(Log::G3D, "%s", errorMessage.c_str());
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
return device->CreatePixelShader(byteCode.data(), byteCode.size(), nullptr, ppPixelShader);
|
|
}
|
|
|
|
HRESULT CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags, ID3D11ComputeShader **ppComputeShader) {
|
|
if (ppComputeShader)
|
|
*ppComputeShader = nullptr;
|
|
if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
|
|
return E_FAIL;
|
|
std::string errorMessage;
|
|
std::vector<uint8_t> byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "cs_4_0", flags, &errorMessage);
|
|
if (byteCode.empty()) {
|
|
if (!errorMessage.empty()) {
|
|
ERROR_LOG(Log::G3D, "%s", errorMessage.c_str());
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
return device->CreateComputeShader(byteCode.data(), byteCode.size(), nullptr, ppComputeShader);
|
|
}
|