Merge pull request #8142 from lioncash/shader-view
VideoCommon/RenderBase: Use std::string_view with CreateShaderFromSource()
This commit is contained in:
commit
2ce587f781
|
@ -113,10 +113,10 @@ std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
const char* source, size_t length)
|
std::string_view source)
|
||||||
{
|
{
|
||||||
DXShader::BinaryData bytecode;
|
DXShader::BinaryData bytecode;
|
||||||
if (!DXShader::CompileShader(D3D::feature_level, &bytecode, stage, source, length))
|
if (!DXShader::CompileShader(D3D::feature_level, &bytecode, stage, source))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return DXShader::CreateFromBytecode(stage, std::move(bytecode));
|
return DXShader::CreateFromBytecode(stage, std::move(bytecode));
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include <string>
|
#include <string_view>
|
||||||
#include "VideoBackends/D3D/D3DState.h"
|
#include "VideoBackends/D3D/D3DState.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ public:
|
||||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -24,11 +24,10 @@ std::unique_ptr<DXShader> DXShader::CreateFromBytecode(ShaderStage stage, Binary
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, std::string_view source)
|
||||||
size_t length)
|
|
||||||
{
|
{
|
||||||
BinaryData bytecode;
|
BinaryData bytecode;
|
||||||
if (!CompileShader(g_dx_context->GetFeatureLevel(), &bytecode, stage, source, length))
|
if (!CompileShader(g_dx_context->GetFeatureLevel(), &bytecode, stage, source))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return CreateFromBytecode(stage, std::move(bytecode));
|
return CreateFromBytecode(stage, std::move(bytecode));
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
#include "VideoBackends/D3D12/Common.h"
|
#include "VideoBackends/D3D12/Common.h"
|
||||||
#include "VideoBackends/D3DCommon/Shader.h"
|
#include "VideoBackends/D3DCommon/Shader.h"
|
||||||
|
|
||||||
|
@ -18,8 +20,7 @@ public:
|
||||||
D3D12_SHADER_BYTECODE GetD3DByteCode() const;
|
D3D12_SHADER_BYTECODE GetD3DByteCode() const;
|
||||||
|
|
||||||
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode);
|
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode);
|
||||||
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, const char* source,
|
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, std::string_view source);
|
||||||
size_t length);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DXShader(ShaderStage stage, BinaryData bytecode);
|
DXShader(ShaderStage stage, BinaryData bytecode);
|
||||||
|
|
|
@ -82,9 +82,9 @@ std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
const char* source, size_t length)
|
std::string_view source)
|
||||||
{
|
{
|
||||||
return DXShader::CreateFromSource(stage, source, length);
|
return DXShader::CreateFromSource(stage, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
|
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
|
@ -35,8 +36,8 @@ public:
|
||||||
std::unique_ptr<AbstractFramebuffer>
|
std::unique_ptr<AbstractFramebuffer>
|
||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -90,7 +90,7 @@ static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode,
|
bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode,
|
||||||
ShaderStage stage, const char* source, size_t length)
|
ShaderStage stage, std::string_view source)
|
||||||
{
|
{
|
||||||
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
|
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
|
||||||
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
|
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
|
||||||
|
@ -100,8 +100,8 @@ bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_byte
|
||||||
|
|
||||||
Microsoft::WRL::ComPtr<ID3DBlob> code;
|
Microsoft::WRL::ComPtr<ID3DBlob> code;
|
||||||
Microsoft::WRL::ComPtr<ID3DBlob> errors;
|
Microsoft::WRL::ComPtr<ID3DBlob> errors;
|
||||||
HRESULT hr = d3d_compile(source, length, nullptr, macros, nullptr, "main", target, flags, 0,
|
HRESULT hr = d3d_compile(source.data(), source.size(), nullptr, macros, nullptr, "main", target,
|
||||||
&code, &errors);
|
flags, 0, &code, &errors);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
static int num_failures = 0;
|
static int num_failures = 0;
|
||||||
|
@ -109,7 +109,7 @@ bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_byte
|
||||||
"%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++);
|
"%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++);
|
||||||
std::ofstream file;
|
std::ofstream file;
|
||||||
File::OpenFStream(file, filename, std::ios_base::out);
|
File::OpenFStream(file, filename, std::ios_base::out);
|
||||||
file.write(source, length);
|
file.write(source.data(), source.size());
|
||||||
file << "\n";
|
file << "\n";
|
||||||
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
|
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
|
||||||
|
#include <string_view>
|
||||||
#include "VideoBackends/D3DCommon/Common.h"
|
#include "VideoBackends/D3DCommon/Common.h"
|
||||||
#include "VideoCommon/AbstractShader.h"
|
#include "VideoCommon/AbstractShader.h"
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ public:
|
||||||
BinaryData GetBinary() const override;
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
static bool CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode,
|
static bool CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode,
|
||||||
ShaderStage stage, const char* source, size_t length);
|
ShaderStage stage, std::string_view source);
|
||||||
|
|
||||||
static BinaryData CreateByteCode(const void* data, size_t length);
|
static BinaryData CreateByteCode(const void* data, size_t length);
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,8 @@ public:
|
||||||
~NullShader() = default;
|
~NullShader() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader>
|
||||||
const char* source, size_t length)
|
Renderer::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source)
|
||||||
{
|
{
|
||||||
return std::make_unique<NullShader>(stage);
|
return std::make_unique<NullShader>(stage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ public:
|
||||||
std::unique_ptr<AbstractFramebuffer>
|
std::unique_ptr<AbstractFramebuffer>
|
||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -45,10 +45,9 @@ OGLShader::~OGLShader()
|
||||||
glDeleteProgram(m_gl_compute_program_id);
|
glDeleteProgram(m_gl_compute_program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, std::string_view source)
|
||||||
size_t length)
|
|
||||||
{
|
{
|
||||||
std::string source_str(source, length);
|
std::string source_str(source);
|
||||||
if (stage != ShaderStage::Compute)
|
if (stage != ShaderStage::Compute)
|
||||||
{
|
{
|
||||||
GLenum shader_type = GetGLShaderTypeForStage(stage);
|
GLenum shader_type = GetGLShaderTypeForStage(stage);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/GL/GLUtil.h"
|
#include "Common/GL/GLUtil.h"
|
||||||
|
@ -26,8 +27,7 @@ public:
|
||||||
GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
|
GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
|
||||||
const std::string& GetSource() const { return m_source; }
|
const std::string& GetSource() const { return m_source; }
|
||||||
|
|
||||||
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, const char* source,
|
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, std::string_view source);
|
||||||
size_t length);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u64 m_id;
|
u64 m_id;
|
||||||
|
|
|
@ -832,9 +832,9 @@ std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
const char* source, size_t length)
|
std::string_view source)
|
||||||
{
|
{
|
||||||
return OGLShader::CreateFromSource(stage, source, length);
|
return OGLShader::CreateFromSource(stage, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
|
|
@ -95,8 +95,8 @@ public:
|
||||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
SWRenderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length)
|
SWRenderer::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source)
|
||||||
{
|
{
|
||||||
return std::make_unique<SWShader>(stage);
|
return std::make_unique<SWShader>(stage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ public:
|
||||||
std::unique_ptr<AbstractFramebuffer>
|
std::unique_ptr<AbstractFramebuffer>
|
||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -95,9 +95,9 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
const char* source, size_t length)
|
std::string_view source)
|
||||||
{
|
{
|
||||||
return VKShader::CreateFromSource(stage, source, length);
|
return VKShader::CreateFromSource(stage, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
|
|
@ -42,8 +42,8 @@ public:
|
||||||
std::unique_ptr<AbstractFramebuffer>
|
std::unique_ptr<AbstractFramebuffer>
|
||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
size_t length) override;
|
std::string_view source) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length) override;
|
size_t length) override;
|
||||||
std::unique_ptr<NativeVertexFormat>
|
std::unique_ptr<NativeVertexFormat>
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "ShaderLang.h"
|
#include "ShaderLang.h"
|
||||||
#include "disassemble.h"
|
#include "disassemble.h"
|
||||||
|
|
||||||
#include "Common/CommonFuncs.h"
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
@ -35,11 +34,6 @@ bool InitializeGlslang();
|
||||||
// Resource limits used when compiling shaders
|
// Resource limits used when compiling shaders
|
||||||
static const TBuiltInResource* GetCompilerResourceLimits();
|
static const TBuiltInResource* GetCompilerResourceLimits();
|
||||||
|
|
||||||
// Compile a shader to SPIR-V via glslang
|
|
||||||
static bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage,
|
|
||||||
const char* stage_filename, const char* source_code,
|
|
||||||
size_t source_code_length, const char* header, size_t header_length);
|
|
||||||
|
|
||||||
// Regarding the UBO bind points, we subtract one from the binding index because
|
// Regarding the UBO bind points, we subtract one from the binding index because
|
||||||
// the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV).
|
// the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV).
|
||||||
// This allows us to share the same shaders but use bind point #0 in the Vulkan
|
// This allows us to share the same shaders but use bind point #0 in the Vulkan
|
||||||
|
@ -113,12 +107,11 @@ static const char SUBGROUP_HELPER_HEADER[] = R"(
|
||||||
#define SUBGROUP_MAX(value) value = subgroupMax(value)
|
#define SUBGROUP_MAX(value) value = subgroupMax(value)
|
||||||
)";
|
)";
|
||||||
|
|
||||||
bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char* stage_filename,
|
std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage, const char* stage_filename,
|
||||||
const char* source_code, size_t source_code_length, const char* header,
|
std::string_view source, std::string_view header)
|
||||||
size_t header_length)
|
|
||||||
{
|
{
|
||||||
if (!InitializeGlslang())
|
if (!InitializeGlslang())
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
|
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
|
||||||
std::unique_ptr<glslang::TProgram> program;
|
std::unique_ptr<glslang::TProgram> program;
|
||||||
|
@ -129,16 +122,16 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
|
||||||
int default_version = 450;
|
int default_version = 450;
|
||||||
|
|
||||||
std::string full_source_code;
|
std::string full_source_code;
|
||||||
const char* pass_source_code = source_code;
|
const char* pass_source_code = source.data();
|
||||||
int pass_source_code_length = static_cast<int>(source_code_length);
|
int pass_source_code_length = static_cast<int>(source.size());
|
||||||
if (header_length > 0)
|
if (!header.empty())
|
||||||
{
|
{
|
||||||
constexpr size_t subgroup_helper_header_length = ArraySize(SUBGROUP_HELPER_HEADER) - 1;
|
constexpr size_t subgroup_helper_header_length = std::size(SUBGROUP_HELPER_HEADER) - 1;
|
||||||
full_source_code.reserve(header_length + subgroup_helper_header_length + source_code_length);
|
full_source_code.reserve(header.size() + subgroup_helper_header_length + source.size());
|
||||||
full_source_code.append(header, header_length);
|
full_source_code.append(header);
|
||||||
if (g_vulkan_context->SupportsShaderSubgroupOperations())
|
if (g_vulkan_context->SupportsShaderSubgroupOperations())
|
||||||
full_source_code.append(SUBGROUP_HELPER_HEADER, subgroup_helper_header_length);
|
full_source_code.append(SUBGROUP_HELPER_HEADER, subgroup_helper_header_length);
|
||||||
full_source_code.append(source_code, source_code_length);
|
full_source_code.append(source);
|
||||||
pass_source_code = full_source_code.c_str();
|
pass_source_code = full_source_code.c_str();
|
||||||
pass_source_code_length = static_cast<int>(full_source_code.length());
|
pass_source_code_length = static_cast<int>(full_source_code.length());
|
||||||
}
|
}
|
||||||
|
@ -178,7 +171,7 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
|
||||||
includer))
|
includer))
|
||||||
{
|
{
|
||||||
DumpBadShader("Failed to parse shader");
|
DumpBadShader("Failed to parse shader");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even though there's only a single shader, we still need to link it to generate SPV
|
// Even though there's only a single shader, we still need to link it to generate SPV
|
||||||
|
@ -187,18 +180,19 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
|
||||||
if (!program->link(messages))
|
if (!program->link(messages))
|
||||||
{
|
{
|
||||||
DumpBadShader("Failed to link program");
|
DumpBadShader("Failed to link program");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
glslang::TIntermediate* intermediate = program->getIntermediate(stage);
|
glslang::TIntermediate* intermediate = program->getIntermediate(stage);
|
||||||
if (!intermediate)
|
if (!intermediate)
|
||||||
{
|
{
|
||||||
DumpBadShader("Failed to generate SPIR-V");
|
DumpBadShader("Failed to generate SPIR-V");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIRVCodeVector out_code;
|
||||||
spv::SpvBuildLogger logger;
|
spv::SpvBuildLogger logger;
|
||||||
glslang::GlslangToSpv(*intermediate, *out_code, &logger);
|
glslang::GlslangToSpv(*intermediate, out_code, &logger);
|
||||||
|
|
||||||
// Write out messages
|
// Write out messages
|
||||||
// Temporary: skip if it contains "Warning, version 450 is not yet complete; most version-specific
|
// Temporary: skip if it contains "Warning, version 450 is not yet complete; most version-specific
|
||||||
|
@ -236,11 +230,11 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
|
||||||
stream << "SPIR-V conversion messages: " << std::endl;
|
stream << "SPIR-V conversion messages: " << std::endl;
|
||||||
stream << spv_messages;
|
stream << spv_messages;
|
||||||
stream << "SPIR-V:" << std::endl;
|
stream << "SPIR-V:" << std::endl;
|
||||||
spv::Disassemble(stream, *out_code);
|
spv::Disassemble(stream, out_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return out_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitializeGlslang()
|
bool InitializeGlslang()
|
||||||
|
@ -362,32 +356,24 @@ const TBuiltInResource* GetCompilerResourceLimits()
|
||||||
return &limits;
|
return &limits;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code)
|
||||||
size_t source_code_length)
|
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(out_code, EShLangVertex, "vs", source_code, source_code_length,
|
return CompileShaderToSPV(EShLangVertex, "vs", source_code, SHADER_HEADER);
|
||||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code)
|
||||||
size_t source_code_length)
|
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(out_code, EShLangGeometry, "gs", source_code, source_code_length,
|
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, SHADER_HEADER);
|
||||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code)
|
||||||
size_t source_code_length)
|
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(out_code, EShLangFragment, "ps", source_code, source_code_length,
|
return CompileShaderToSPV(EShLangFragment, "ps", source_code, SHADER_HEADER);
|
||||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code)
|
||||||
size_t source_code_length)
|
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(out_code, EShLangCompute, "cs", source_code, source_code_length,
|
return CompileShaderToSPV(EShLangCompute, "cs", source_code, COMPUTE_SHADER_HEADER);
|
||||||
COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ShaderCompiler
|
} // namespace ShaderCompiler
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -18,20 +20,16 @@ using SPIRVCodeType = u32;
|
||||||
using SPIRVCodeVector = std::vector<SPIRVCodeType>;
|
using SPIRVCodeVector = std::vector<SPIRVCodeType>;
|
||||||
|
|
||||||
// Compile a vertex shader to SPIR-V.
|
// Compile a vertex shader to SPIR-V.
|
||||||
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code);
|
||||||
size_t source_code_length);
|
|
||||||
|
|
||||||
// Compile a geometry shader to SPIR-V.
|
// Compile a geometry shader to SPIR-V.
|
||||||
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code);
|
||||||
size_t source_code_length);
|
|
||||||
|
|
||||||
// Compile a fragment shader to SPIR-V.
|
// Compile a fragment shader to SPIR-V.
|
||||||
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code);
|
||||||
size_t source_code_length);
|
|
||||||
|
|
||||||
// Compile a compute shader to SPIR-V.
|
// Compile a compute shader to SPIR-V.
|
||||||
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
|
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code);
|
||||||
size_t source_code_length);
|
|
||||||
|
|
||||||
} // namespace ShaderCompiler
|
} // namespace ShaderCompiler
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -86,34 +86,31 @@ static std::unique_ptr<VKShader> CreateShaderObject(ShaderStage stage,
|
||||||
return std::make_unique<VKShader>(std::move(spv), pipeline);
|
return std::make_unique<VKShader>(std::move(spv), pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, const char* source,
|
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, std::string_view source)
|
||||||
size_t length)
|
|
||||||
{
|
{
|
||||||
ShaderCompiler::SPIRVCodeVector spv;
|
std::optional<ShaderCompiler::SPIRVCodeVector> spv;
|
||||||
bool result;
|
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
result = ShaderCompiler::CompileVertexShader(&spv, source, length);
|
spv = ShaderCompiler::CompileVertexShader(source);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Geometry:
|
case ShaderStage::Geometry:
|
||||||
result = ShaderCompiler::CompileGeometryShader(&spv, source, length);
|
spv = ShaderCompiler::CompileGeometryShader(source);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Pixel:
|
case ShaderStage::Pixel:
|
||||||
result = ShaderCompiler::CompileFragmentShader(&spv, source, length);
|
spv = ShaderCompiler::CompileFragmentShader(source);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Compute:
|
case ShaderStage::Compute:
|
||||||
result = ShaderCompiler::CompileComputeShader(&spv, source, length);
|
spv = ShaderCompiler::CompileComputeShader(source);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!spv)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return CreateShaderObject(stage, std::move(spv));
|
return CreateShaderObject(stage, std::move(*spv));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VKShader> VKShader::CreateFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<VKShader> VKShader::CreateFromBinary(ShaderStage stage, const void* data,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -25,8 +26,7 @@ public:
|
||||||
VkPipeline GetComputePipeline() const { return m_compute_pipeline; }
|
VkPipeline GetComputePipeline() const { return m_compute_pipeline; }
|
||||||
BinaryData GetBinary() const override;
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, const char* source,
|
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, std::string_view source);
|
||||||
size_t length);
|
|
||||||
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length);
|
size_t length);
|
||||||
|
|
||||||
|
|
|
@ -148,12 +148,6 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||||
m_current_framebuffer = framebuffer;
|
m_current_framebuffer = framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
|
||||||
const std::string& source)
|
|
||||||
{
|
|
||||||
return CreateShaderFromSource(stage, source.c_str(), source.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::EFBHasAlphaChannel() const
|
bool Renderer::EFBHasAlphaChannel() const
|
||||||
{
|
{
|
||||||
return m_prev_efb_format == PEControl::RGBA6_Z24;
|
return m_prev_efb_format == PEControl::RGBA6_Z24;
|
||||||
|
@ -980,10 +974,10 @@ bool Renderer::InitializeImGui()
|
||||||
|
|
||||||
const std::string vertex_shader_source = GenerateImGuiVertexShader();
|
const std::string vertex_shader_source = GenerateImGuiVertexShader();
|
||||||
const std::string pixel_shader_source = GenerateImGuiPixelShader();
|
const std::string pixel_shader_source = GenerateImGuiPixelShader();
|
||||||
std::unique_ptr<AbstractShader> vertex_shader = CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> vertex_shader =
|
||||||
ShaderStage::Vertex, vertex_shader_source.c_str(), vertex_shader_source.size());
|
CreateShaderFromSource(ShaderStage::Vertex, vertex_shader_source);
|
||||||
std::unique_ptr<AbstractShader> pixel_shader = CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> pixel_shader =
|
||||||
ShaderStage::Pixel, pixel_shader_source.c_str(), pixel_shader_source.size());
|
CreateShaderFromSource(ShaderStage::Pixel, pixel_shader_source);
|
||||||
if (!vertex_shader || !pixel_shader)
|
if (!vertex_shader || !pixel_shader)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to compile imgui shaders");
|
PanicAlert("Failed to compile imgui shaders");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -123,8 +124,8 @@ public:
|
||||||
virtual void PresentBackbuffer() {}
|
virtual void PresentBackbuffer() {}
|
||||||
|
|
||||||
// Shader modules/objects.
|
// Shader modules/objects.
|
||||||
virtual std::unique_ptr<AbstractShader>
|
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||||
CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) = 0;
|
std::string_view source) = 0;
|
||||||
virtual std::unique_ptr<AbstractShader>
|
virtual std::unique_ptr<AbstractShader>
|
||||||
CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) = 0;
|
CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) = 0;
|
||||||
virtual std::unique_ptr<NativeVertexFormat>
|
virtual std::unique_ptr<NativeVertexFormat>
|
||||||
|
@ -132,8 +133,6 @@ public:
|
||||||
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||||
const void* cache_data = nullptr,
|
const void* cache_data = nullptr,
|
||||||
size_t cache_data_length = 0) = 0;
|
size_t cache_data_length = 0) = 0;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
|
||||||
const std::string& source);
|
|
||||||
|
|
||||||
AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
|
AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
|
||||||
|
|
||||||
|
|
|
@ -392,32 +392,32 @@ void ShaderCache::CompileMissingPipelines()
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> ShaderCache::CompileVertexShader(const VertexShaderUid& uid) const
|
std::unique_ptr<AbstractShader> ShaderCache::CompileVertexShader(const VertexShaderUid& uid) const
|
||||||
{
|
{
|
||||||
ShaderCode source_code = GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code =
|
||||||
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer().c_str(),
|
GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||||
source_code.GetBuffer().size());
|
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const
|
ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const
|
||||||
{
|
{
|
||||||
ShaderCode source_code = UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code =
|
||||||
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer().c_str(),
|
UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
|
||||||
source_code.GetBuffer().size());
|
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
|
std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
|
||||||
{
|
{
|
||||||
ShaderCode source_code = GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code =
|
||||||
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer().c_str(),
|
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||||
source_code.GetBuffer().size());
|
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
||||||
{
|
{
|
||||||
ShaderCode source_code = UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code =
|
||||||
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer().c_str(),
|
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
||||||
source_code.GetBuffer().size());
|
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbstractShader* ShaderCache::InsertVertexShader(const VertexShaderUid& uid,
|
const AbstractShader* ShaderCache::InsertVertexShader(const VertexShaderUid& uid,
|
||||||
|
@ -510,9 +510,10 @@ const AbstractShader* ShaderCache::InsertPixelUberShader(const UberShader::Pixel
|
||||||
|
|
||||||
const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid& uid)
|
const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid& uid)
|
||||||
{
|
{
|
||||||
ShaderCode source_code = GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code =
|
||||||
std::unique_ptr<AbstractShader> shader = g_renderer->CreateShaderFromSource(
|
GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||||
ShaderStage::Geometry, source_code.GetBuffer().c_str(), source_code.GetBuffer().size());
|
std::unique_ptr<AbstractShader> shader =
|
||||||
|
g_renderer->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer());
|
||||||
|
|
||||||
auto& entry = m_gs_cache.shader_map[uid];
|
auto& entry = m_gs_cache.shader_map[uid];
|
||||||
entry.pending = false;
|
entry.pending = false;
|
||||||
|
@ -1150,9 +1151,9 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
|
||||||
if (iter != m_efb_copy_to_ram_pipelines.end())
|
if (iter != m_efb_copy_to_ram_pipelines.end())
|
||||||
return iter->second.get();
|
return iter->second.get();
|
||||||
|
|
||||||
auto shader_code = TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
|
const char* const shader_code =
|
||||||
auto shader =
|
TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
|
||||||
g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code, std::strlen(shader_code));
|
const auto shader = g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code);
|
||||||
if (!shader)
|
if (!shader)
|
||||||
{
|
{
|
||||||
m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);
|
m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);
|
||||||
|
|
Loading…
Reference in New Issue