You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2164 lines
79 KiB
C++
2164 lines
79 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : Implements the shader related functions
|
|
|
|
|
|
#include "RenderDll_precompiled.h"
|
|
#include "GLShader.hpp"
|
|
#include "GLDevice.hpp"
|
|
#include <Common/RenderCapabilities.h>
|
|
|
|
#if DXGL_INPUT_GLSL && DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
#include "hlslcc.hpp"
|
|
#endif //DXGL_INPUT_GLSL && DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
#include "hlslcc_bin.hpp"
|
|
|
|
struct SAutoBindProgram
|
|
{
|
|
SAutoBindProgram(const GLuint uProgram)
|
|
{
|
|
GLint iBinding;
|
|
glGetIntegerv(GL_CURRENT_PROGRAM, &iBinding);
|
|
m_uPreviousBinding = (GLuint)iBinding;
|
|
glUseProgram(uProgram);
|
|
}
|
|
|
|
~SAutoBindProgram()
|
|
{
|
|
glUseProgram(m_uPreviousBinding);
|
|
}
|
|
|
|
GLuint m_uPreviousBinding;
|
|
};
|
|
|
|
#if DXGL_GLSL_FROM_HLSL2GLSL && DXGL_SUPPORT_NSIGHT_SINCE(4_1)
|
|
// NSight shader instrumentation throws an exception when compiling shaders with functions with many parameters.
|
|
// Shaders generated with HLSL2GLSL are simplified using glslOptimizer to exploit its function inlining and simplify instrumentation.
|
|
#include "../../Tools/glslOptimizer/src/glsl/glsl_optimizer.h"
|
|
struct SSimplifiedShader
|
|
{
|
|
glslopt_shader* m_pOptimizedShader;
|
|
|
|
SSimplifiedShader()
|
|
: m_pOptimizedShader(NULL)
|
|
{
|
|
}
|
|
|
|
~SSimplifiedShader()
|
|
{
|
|
if (m_pOptimizedShader != NULL)
|
|
{
|
|
glslopt_shader_delete(m_pOptimizedShader);
|
|
}
|
|
}
|
|
|
|
const char* Simplify(const char* szSource, NCryOpenGL::EShaderType eType)
|
|
{
|
|
struct SAutoContext
|
|
{
|
|
glslopt_ctx* m_pContext;
|
|
SAutoContext() { m_pContext = glslopt_initialize(kGlslTargetOpenGL); }
|
|
~SAutoContext() { glslopt_cleanup(m_pContext); }
|
|
};
|
|
|
|
glslopt_shader_type eOptType;
|
|
switch (eType)
|
|
{
|
|
case NCryOpenGL::eST_Vertex:
|
|
eOptType = kGlslOptShaderVertex;
|
|
break;
|
|
case NCryOpenGL::eST_Fragment:
|
|
eOptType = kGlslOptShaderFragment;
|
|
break;
|
|
default:
|
|
DXGL_ERROR("Invalid shader type for glslOptimizer");
|
|
return NULL;
|
|
}
|
|
|
|
static SAutoContext s_kContext;
|
|
m_pOptimizedShader = glslopt_optimize(s_kContext.m_pContext, eOptType, szSource, 0);
|
|
|
|
if (!glslopt_get_status(m_pOptimizedShader))
|
|
{
|
|
DXGL_ERROR("Error during glslOptimizer execution: %s", glslopt_get_log(m_pOptimizedShader));
|
|
m_pOptimizedShader = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
return glslopt_get_output (m_pOptimizedShader);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
namespace NCryOpenGL
|
|
{
|
|
SSource::SSource(const char* pData, uint32 uDataSize)
|
|
: m_uDataSize(uDataSize)
|
|
, m_pData(pData)
|
|
{
|
|
}
|
|
|
|
SSource::~SSource()
|
|
{
|
|
}
|
|
|
|
struct SDXBCInfo
|
|
{
|
|
uint32 m_uMajorVersion, m_uMinorVersion;
|
|
};
|
|
|
|
struct SDXBCParseContext
|
|
: SDXBCInputBuffer
|
|
{
|
|
SDXBCInfo* m_pInfo;
|
|
|
|
SDXBCParseContext(const uint8* pBegin, const uint8* pEnd, SDXBCInfo* pInfo)
|
|
: SDXBCInputBuffer(pBegin, pEnd)
|
|
, m_pInfo(pInfo)
|
|
{
|
|
}
|
|
|
|
SDXBCParseContext(const SDXBCParseContext& kOther, uint32 uOffset)
|
|
: SDXBCInputBuffer(kOther.m_pBegin + uOffset, kOther.m_pEnd)
|
|
, m_pInfo(kOther.m_pInfo)
|
|
{
|
|
m_pIter = m_pBegin;
|
|
}
|
|
|
|
bool ReadString(char* pBuffer, uint32 uBufSize)
|
|
{
|
|
uint32 uSize((uint32)strlen(alias_cast<const char*>(m_pIter)) + 1);
|
|
if (uSize > uBufSize)
|
|
{
|
|
return false;
|
|
}
|
|
return Read(pBuffer, uSize);
|
|
}
|
|
};
|
|
|
|
bool DXBCRetrieveInfo(SDXBCParseContext& kContext)
|
|
{
|
|
uint32 uNumChunks;
|
|
DXBCReadUint32(kContext, uNumChunks);
|
|
|
|
uint32 uChunk;
|
|
for (uChunk = 0; uChunk < uNumChunks; ++uChunk)
|
|
{
|
|
uint32 uChunkBegin;
|
|
DXBCReadUint32(kContext, uChunkBegin);
|
|
|
|
SDXBCParseContext kChunkHeaderContext(kContext, uChunkBegin);
|
|
|
|
uint32 uChunkFourCC, uChunkSize;
|
|
DXBCReadUint32(kChunkHeaderContext, uChunkFourCC);
|
|
DXBCReadUint32(kChunkHeaderContext, uChunkSize);
|
|
|
|
if (uChunkFourCC == FOURCC_SHDR || uChunkFourCC == FOURCC_SHEX)
|
|
{
|
|
uint32 uEncodedInfo;
|
|
DXBCReadUint32(kChunkHeaderContext, uEncodedInfo);
|
|
|
|
kContext.m_pInfo->m_uMajorVersion = (uEncodedInfo >> 4) & 0xF;
|
|
kContext.m_pInfo->m_uMinorVersion = uEncodedInfo & 0xF;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
SShaderSource::SShaderSource()
|
|
{
|
|
}
|
|
|
|
SShaderSource::~SShaderSource()
|
|
{
|
|
delete [] m_pData;
|
|
}
|
|
|
|
void SShaderSource::SetData(const char* pData, uint32 uDataSize)
|
|
{
|
|
delete [] m_pData;
|
|
if (uDataSize > 0)
|
|
{
|
|
char* pBuffer = new char[uDataSize];
|
|
memcpy(pBuffer, pData, uDataSize);
|
|
m_pData = pBuffer;
|
|
}
|
|
else
|
|
{
|
|
m_pData = NULL;
|
|
}
|
|
m_uDataSize = uDataSize;
|
|
}
|
|
|
|
|
|
SGLShader::SGLShader()
|
|
: m_uName(0)
|
|
, m_separableProgramsSupported(false)
|
|
{
|
|
}
|
|
|
|
SGLShader::~SGLShader()
|
|
{
|
|
if (m_uName != 0)
|
|
{
|
|
if (m_separableProgramsSupported)
|
|
{
|
|
glDeleteProgram(m_uName);
|
|
}
|
|
else
|
|
{
|
|
glDeleteShader(m_uName);
|
|
}
|
|
}
|
|
}
|
|
|
|
SShader::SShader()
|
|
: m_eType(eST_NUM)
|
|
{
|
|
}
|
|
|
|
SShader::~SShader()
|
|
{
|
|
// All pipelines with this shader bound must be removed from the cache and deleted
|
|
TPipelines::const_iterator kPipelineIter(m_kBoundPipelines.begin());
|
|
const TPipelines::const_iterator kPipelineEnd(m_kBoundPipelines.end());
|
|
while (kPipelineIter != kPipelineEnd)
|
|
{
|
|
(*kPipelineIter)->m_pContext->RemovePipeline(*kPipelineIter, this);
|
|
++kPipelineIter;
|
|
}
|
|
}
|
|
|
|
void SShader::AttachPipeline(SPipeline* pPipeline)
|
|
{
|
|
TPipelines::const_iterator kFound(std::find(m_kBoundPipelines.begin(), m_kBoundPipelines.end(), pPipeline));
|
|
if (kFound == m_kBoundPipelines.end())
|
|
{
|
|
m_kBoundPipelines.push_back(pPipeline);
|
|
}
|
|
}
|
|
|
|
void SShader::DetachPipeline(SPipeline* pPipeline)
|
|
{
|
|
TPipelines::iterator kFound(std::find(m_kBoundPipelines.begin(), m_kBoundPipelines.end(), pPipeline));
|
|
if (kFound != m_kBoundPipelines.end())
|
|
{
|
|
m_kBoundPipelines.erase(kFound);
|
|
}
|
|
else
|
|
{
|
|
DXGL_ERROR("Could not find the pipeline to be detached from the shader");
|
|
}
|
|
}
|
|
|
|
SPipeline::SPipeline(const SPipelineConfiguration& kConfiguration, CContext* pContext)
|
|
: m_kConfiguration(kConfiguration)
|
|
, m_pContext(pContext)
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
, m_uTraceBufferUnit(0)
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
{
|
|
}
|
|
|
|
SPipeline::~SPipeline()
|
|
{
|
|
if (m_pContext->GetDevice()->IsFeatureSupported(eF_SeparablePrograms))
|
|
{
|
|
glDeleteProgramPipelines(1, &m_uName);
|
|
}
|
|
else
|
|
{
|
|
glDeleteProgram(m_uName);
|
|
}
|
|
}
|
|
|
|
bool InitializeShaderReflectionVariable(SShaderReflectionVariable* pVariable, SDXBCParseContext* pContext)
|
|
{
|
|
uint32 uNamePos;
|
|
if (!DXBCReadUint32(*pContext, uNamePos) ||
|
|
!SDXBCParseContext(*pContext, uNamePos).ReadString(pVariable->m_acName, DXGL_ARRAY_SIZE(pVariable->m_acName)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 uPosType;
|
|
memset(&pVariable->m_kDesc, 0, sizeof(D3D11_SHADER_VARIABLE_DESC));
|
|
pVariable->m_kDesc.Name = pVariable->m_acName;
|
|
if (!DXBCReadUint32(*pContext, pVariable->m_kDesc.StartOffset) ||
|
|
!DXBCReadUint32(*pContext, pVariable->m_kDesc.Size) ||
|
|
!DXBCReadUint32(*pContext, pVariable->m_kDesc.uFlags) ||
|
|
!DXBCReadUint32(*pContext, uPosType))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
{
|
|
SDXBCParseContext kTypeContext(*pContext);
|
|
memset(&pVariable->m_kType, 0, sizeof(D3D11_SHADER_TYPE_DESC));
|
|
|
|
if (!kTypeContext.SeekAbs(uPosType) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Class) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Type) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Rows) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Columns) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Elements) ||
|
|
!DXBCReadUint16(kTypeContext, pVariable->m_kType.Members) ||
|
|
!DXBCReadUint32(kTypeContext, pVariable->m_kType.Offset))
|
|
{
|
|
return false;
|
|
}
|
|
pVariable->m_kType.Name = NULL;
|
|
}
|
|
|
|
uint32 uPosDefaultValue;
|
|
if (!DXBCReadUint32(*pContext, uPosDefaultValue))
|
|
{
|
|
return false;
|
|
}
|
|
if (uPosDefaultValue != 0)
|
|
{
|
|
pVariable->m_kDefaultValue.resize(pVariable->m_kDesc.Size);
|
|
if (!pContext->Read(pVariable->m_kDefaultValue.data(), pVariable->m_kDesc.Size))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pVariable->m_kDesc.DefaultValue = NULL;
|
|
}
|
|
|
|
if (pContext->m_pInfo->m_uMajorVersion >= 5)
|
|
{
|
|
if (!DXBCReadUint32(*pContext, pVariable->m_kDesc.StartTexture) ||
|
|
!DXBCReadUint32(*pContext, pVariable->m_kDesc.TextureSize) ||
|
|
!DXBCReadUint32(*pContext, pVariable->m_kDesc.StartSampler) ||
|
|
!DXBCReadUint32(*pContext, pVariable->m_kDesc.SamplerSize))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InitializeShaderReflectionConstBuffer(SShaderReflectionConstBuffer* pConstBuffer, SDXBCParseContext* pContext)
|
|
{
|
|
uint32 uNamePos;
|
|
if (!DXBCReadUint32(*pContext, uNamePos) ||
|
|
!SDXBCParseContext(*pContext, uNamePos).ReadString(pConstBuffer->m_acName, DXGL_ARRAY_SIZE(pConstBuffer->m_acName)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
memset(&pConstBuffer->m_kDesc, 0, sizeof(pConstBuffer->m_kDesc));
|
|
pConstBuffer->m_kDesc.Name = pConstBuffer->m_acName;
|
|
|
|
uint32 uNumVariables, uPosVariables;
|
|
if (!DXBCReadUint32(*pContext, uNumVariables) ||
|
|
!DXBCReadUint32(*pContext, uPosVariables))
|
|
{
|
|
return false;
|
|
}
|
|
pConstBuffer->m_kDesc.Variables = uNumVariables;
|
|
|
|
SDXBCParseContext kVariablesContext(*pContext);
|
|
if (!kVariablesContext.SeekAbs(uPosVariables))
|
|
{
|
|
return false;
|
|
}
|
|
uint32 uVariable;
|
|
pConstBuffer->m_kVariables.resize(pConstBuffer->m_kDesc.Variables);
|
|
for (uVariable = 0; uVariable < pConstBuffer->m_kDesc.Variables; ++uVariable)
|
|
{
|
|
if (!InitializeShaderReflectionVariable(&pConstBuffer->m_kVariables.at(uVariable), &kVariablesContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!DXBCReadUint32(*pContext, pConstBuffer->m_kDesc.Size) ||
|
|
!DXBCReadUint32(*pContext, pConstBuffer->m_kDesc.uFlags) ||
|
|
!DXBCReadUint32(*pContext, pConstBuffer->m_kDesc.Type))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InitializeShaderReflectionResource(SShaderReflectionResource* pParameter, SDXBCParseContext* pContext)
|
|
{
|
|
uint32 uNamePos;
|
|
if (!DXBCReadUint32(*pContext, uNamePos) ||
|
|
!SDXBCParseContext(*pContext, uNamePos).ReadString(pParameter->m_acName, DXGL_ARRAY_SIZE(pParameter->m_acName)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
memset(&pParameter->m_kDesc, 0, sizeof(pParameter->m_kDesc));
|
|
|
|
pParameter->m_kDesc.Name = pParameter->m_acName;
|
|
if (!DXBCReadUint32(*pContext, pParameter->m_kDesc.Type) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.ReturnType) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.Dimension) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.NumSamples) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.BindPoint) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.BindCount) ||
|
|
!DXBCReadUint32(*pContext, pParameter->m_kDesc.uFlags))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InitializeShaderReflectionParameters(SShaderReflection::TParameters& kParameters, SDXBCParseContext* pContext, bool extended = false)
|
|
{
|
|
uint32 uNumElements, uVersion;
|
|
if (!DXBCReadUint32(*pContext, uNumElements) ||
|
|
!DXBCReadUint32(*pContext, uVersion))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (uNumElements > 0)
|
|
{
|
|
uint32 uPrevNumElements(kParameters.size());
|
|
kParameters.resize(kParameters.size() + uNumElements);
|
|
|
|
uint32 uElement;
|
|
for (uElement = uPrevNumElements; uElement < kParameters.size(); ++uElement)
|
|
{
|
|
SShaderReflectionParameter& kParameter(kParameters.at(uElement));
|
|
|
|
memset(&kParameter.m_kDesc, 0, sizeof(kParameter.m_kDesc));
|
|
|
|
// Only for extended parameters fxc adds two extra pieces of information, the stream index and the minimum precision.
|
|
if (extended && !DXBCReadUint32(*pContext, kParameter.m_kDesc.Stream))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 uSemNamePosition;
|
|
if (!DXBCReadUint32(*pContext, uSemNamePosition) ||
|
|
!SDXBCParseContext(*pContext, uSemNamePosition).ReadString(kParameter.m_acSemanticName, DXGL_ARRAY_SIZE(kParameter.m_acSemanticName)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
kParameter.m_kDesc.SemanticName = kParameter.m_acSemanticName;
|
|
if (!DXBCReadUint32(*pContext, kParameter.m_kDesc.SemanticIndex) ||
|
|
!DXBCReadUint32(*pContext, kParameter.m_kDesc.SystemValueType) ||
|
|
!DXBCReadUint32(*pContext, kParameter.m_kDesc.ComponentType) ||
|
|
!DXBCReadUint32(*pContext, kParameter.m_kDesc.Register) ||
|
|
!DXBCReadUint8(*pContext, kParameter.m_kDesc.Mask) ||
|
|
!DXBCReadUint8(*pContext, kParameter.m_kDesc.ReadWriteMask) ||
|
|
!pContext->SeekRel(sizeof(uint16_t)) || // These two bytes are part of the mask but are not used, so we skip them.
|
|
(extended && !DXBCReadUint32(*pContext, kParameter.m_kDesc.MinPrecision))) // Precision available only for extended parameters.
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool InitializeShaderReflection(SShaderReflection* pReflection, const void* pvData, uint32 uSize)
|
|
{
|
|
enum
|
|
{
|
|
CHUNKS_POSITION = sizeof(uint32) * 7
|
|
};
|
|
SDXBCInfo kInfo;
|
|
const uint8* puData(alias_cast<const uint8*>(pvData));
|
|
SDXBCParseContext kContext(puData, puData + uSize, &kInfo);
|
|
|
|
if (!kContext.SeekAbs(CHUNKS_POSITION))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
{
|
|
SDXBCParseContext kParseContext(kContext);
|
|
if (!DXBCRetrieveInfo(kParseContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
uint32 uNumChunks;
|
|
if (!DXBCReadUint32(kContext, uNumChunks))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 uOffset;
|
|
for (uint32 uChunk = 0; uChunk < uNumChunks; ++uChunk)
|
|
{
|
|
uint32 uChunkBegin;
|
|
if (!DXBCReadUint32(kContext, uChunkBegin))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SDXBCParseContext kChunkHeaderContext(kContext, uChunkBegin);
|
|
|
|
uint32 uChunkFourCC, uChunkSize;
|
|
if (!DXBCReadUint32(kChunkHeaderContext, uChunkFourCC) ||
|
|
!DXBCReadUint32(kChunkHeaderContext, uChunkSize))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SDXBCParseContext kChunkContext(kChunkHeaderContext.m_pIter, kChunkHeaderContext.m_pEnd, &kInfo);
|
|
switch (uChunkFourCC)
|
|
{
|
|
case FOURCC_RDEF:
|
|
{
|
|
uint32 uNumConstBuffers, uPosConstBuffers, uNumResources, uPosResources;
|
|
if (!DXBCReadUint32(kChunkContext, uNumConstBuffers) ||
|
|
!DXBCReadUint32(kChunkContext, uPosConstBuffers) ||
|
|
!DXBCReadUint32(kChunkContext, uNumResources) ||
|
|
!DXBCReadUint32(kChunkContext, uPosResources))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SDXBCParseContext kConstBufferContext(kChunkContext);
|
|
if (!kConstBufferContext.SeekAbs(uPosConstBuffers))
|
|
{
|
|
return false;
|
|
}
|
|
uint32 uConstBuffer;
|
|
uint32 uPrevNumConstBuffers(pReflection->m_kConstantBuffers.size());
|
|
pReflection->m_kConstantBuffers.resize(uNumConstBuffers);
|
|
for (uConstBuffer = uPrevNumConstBuffers; uConstBuffer < uNumConstBuffers; ++uConstBuffer)
|
|
{
|
|
if (!InitializeShaderReflectionConstBuffer(&pReflection->m_kConstantBuffers.at(uConstBuffer), &kConstBufferContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SDXBCParseContext kResourceContext(kChunkContext);
|
|
if (!kResourceContext.SeekAbs(uPosResources))
|
|
{
|
|
return false;
|
|
}
|
|
uint32 uResource;
|
|
uint32 uPrevNumResources(pReflection->m_kResources.size());
|
|
pReflection->m_kResources.resize(uNumResources);
|
|
for (uResource = uPrevNumResources; uResource < uNumResources; ++uResource)
|
|
{
|
|
if (!InitializeShaderReflectionResource(&pReflection->m_kResources.at(uResource), &kResourceContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case FOURCC_ISGN:
|
|
case FOURCC_ISG1:
|
|
if (!InitializeShaderReflectionParameters(pReflection->m_kInputs, &kChunkContext, uChunkFourCC == FOURCC_ISG1))
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
case FOURCC_OSGN:
|
|
case FOURCC_OSG1:
|
|
if (!InitializeShaderReflectionParameters(pReflection->m_kOutputs, &kChunkContext, uChunkFourCC == FOURCC_OSG1))
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
case FOURCC_PCSG:
|
|
if (!InitializeShaderReflectionParameters(pReflection->m_kPatchConstants, &kChunkContext))
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
case FOURCC_GLSL:
|
|
if (!DXBCReadUint32(kChunkContext, pReflection->m_uNumSamplers) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uNumImages) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uNumStorageBuffers) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uNumUniformBuffers) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uImportsSize) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uExportsSize) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uInputHash) ||
|
|
!DXBCReadUint32(kChunkContext, pReflection->m_uSymbolsOffset))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uOffset = (uint32)(kChunkContext.m_pIter - kContext.m_pBegin);
|
|
pReflection->m_uSamplersOffset = uOffset;
|
|
uOffset += GLSL_SAMPLER_SIZE * pReflection->m_uNumSamplers;
|
|
pReflection->m_uImagesOffset = uOffset;
|
|
uOffset += GLSL_RESOURCE_SIZE * pReflection->m_uNumImages;
|
|
pReflection->m_uStorageBuffersOffset = uOffset;
|
|
uOffset += GLSL_RESOURCE_SIZE * pReflection->m_uNumStorageBuffers;
|
|
pReflection->m_uUniformBuffersOffset = uOffset;
|
|
uOffset += GLSL_RESOURCE_SIZE * pReflection->m_uNumUniformBuffers;
|
|
pReflection->m_uImportsOffset = uOffset;
|
|
uOffset += GLSL_SYMBOL_SIZE * pReflection->m_uImportsSize;
|
|
pReflection->m_uExportsOffset = uOffset;
|
|
uOffset += GLSL_SYMBOL_SIZE * pReflection->m_uExportsSize;
|
|
pReflection->m_uGLSLSourceOffset = uOffset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
memset(&pReflection->m_kDesc, 0, sizeof(D3D11_SHADER_DESC));
|
|
pReflection->m_kDesc.ConstantBuffers = pReflection->m_kConstantBuffers.size();
|
|
pReflection->m_kDesc.BoundResources = pReflection->m_kResources.size();
|
|
pReflection->m_kDesc.InputParameters = pReflection->m_kInputs.size();
|
|
pReflection->m_kDesc.OutputParameters = pReflection->m_kOutputs.size();
|
|
pReflection->m_kDesc.PatchConstantParameters = pReflection->m_kPatchConstants.size();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#if !DXGL_INPUT_GLSL
|
|
|
|
struct SGLSLConversionOutput
|
|
{
|
|
#if DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
GLSLShader m_kGLSLShader;
|
|
#endif //DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
|
|
SGLSLConversionOutput()
|
|
{
|
|
#if DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
memset(&m_kGLSLShader, 0, sizeof(m_kGLSLShader));
|
|
#endif //DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
}
|
|
|
|
~SGLSLConversionOutput()
|
|
{
|
|
#if DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
FreeGLSLShader(&m_kGLSLShader);
|
|
#endif //DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
}
|
|
};
|
|
|
|
bool ConvertDXBCToGLSL(const void* pvSourceData, size_t uSourceSize, EShaderVersion eVersion, SGLSLConversionOutput* pOutput)
|
|
{
|
|
#if DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
unsigned int uFlags(HLSLCC_FLAG_UNIFORM_BUFFER_OBJECT);
|
|
GlExtensions kExtensions = {0};
|
|
|
|
#if CRY_OPENGL_ADAPT_CLIP_SPACE
|
|
uFlags |= HLSLCC_FLAG_CONVERT_CLIP_SPACE_Z;
|
|
#if CRY_OPENGL_FLIP_Y
|
|
DXGL_TODO("Only do this if the shader is expected to be used to render into a texture so that a final blit for flipping is not required")
|
|
uFlags |= HLSLCC_FLAG_INVERT_CLIP_SPACE_Y;
|
|
#else
|
|
uFlags |= HLSLCC_FLAG_ORIGIN_UPPER_LEFT;
|
|
#endif
|
|
#endif //CRY_OPENGL_ADAPT_CLIP_SPACE
|
|
|
|
DXGL_TODO("Currently we always specify bindings at run-time (slot ranges are determined during startup), and leave the default location for resources (mainly to prevent collisions between resources with the same register index in different non-separable shader stages). Evaluate the possibility of coding them into the shader source.");
|
|
uFlags |= HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS;
|
|
|
|
DXGL_TODO("This is currently the only correct setting as register aliasing is buggy when branches are present.");
|
|
uFlags |= HLSLCC_FLAG_AVOID_TEMP_REGISTER_ALIASING;
|
|
|
|
#if DXGL_HLSL_TO_GLSL_DEBUG
|
|
uFlags |= HLSLCC_FLAG_HASH_INPUT;
|
|
uFlags |= HLSLCC_FLAG_ADD_DEBUG_HEADER;
|
|
#endif //DXGL_HLSL_TO_GLSL_DEBUG
|
|
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
if (eVersion == eSV_Tracing)
|
|
{
|
|
uFlags |= HLSLCC_FLAG_TRACING_INSTRUMENTATION;
|
|
}
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
|
|
// Some drivers (e.g. AMD Catalyst) have issues with certain version strings so we append a different version string at runtime as workaround
|
|
uFlags |= HLSLCC_FLAG_NO_VERSION_STRING;
|
|
|
|
//#if DXGLES
|
|
// uFlags |= HLSLCC_FLAG_INOUT_SEMANTIC_NAMES;
|
|
//#endif
|
|
|
|
GLLang eLanguage;
|
|
#if DXGL_REQUIRED_VERSION >= DXGL_VERSION_44
|
|
eLanguage = LANG_440;
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_43
|
|
eLanguage = LANG_430;
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_42
|
|
eLanguage = LANG_420;
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_41
|
|
eLanguage = LANG_410;
|
|
#elif DXGLES
|
|
uint32 glVersion = RenderCapabilities::GetDeviceGLVersion();
|
|
if (glVersion == DXGLES_VERSION_30)
|
|
{
|
|
eLanguage = LANG_ES_300;
|
|
}
|
|
else
|
|
{
|
|
eLanguage = LANG_ES_310;
|
|
}
|
|
#else
|
|
#error "Shading language revision not defined for this GL version"
|
|
#endif
|
|
|
|
HLSLcc_SetMemoryFunctions(&Malloc, &Calloc, &Free, &Realloc);
|
|
|
|
if (TranslateHLSLFromMem(static_cast<const char*>(pvSourceData), uSourceSize, uFlags, eLanguage, &kExtensions, &pOutput->m_kGLSLShader) != 1)
|
|
{
|
|
DXGL_ERROR("HLSL to GLSL conversion failed");
|
|
return false;
|
|
}
|
|
|
|
#else
|
|
#pragma error "Not implemented on this configuration"
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InitializeTranslatedShaderSource(SShaderSource* pSource, const void* pvDXBCData, size_t uDXBCSize, const SGLSLConversionOutput& kConversionOutput)
|
|
{
|
|
#if DXGL_GLSL_FROM_HLSLCROSSCOMPILER
|
|
const uint8* puDXBC(static_cast<const uint8*>(pvDXBCData));
|
|
|
|
SDXBCInputBuffer kInputBuffer(puDXBC, puDXBC + uDXBCSize);
|
|
size_t uCombinedSize(DXBCGetCombinedSize(kInputBuffer, &kConversionOutput.m_kGLSLShader));
|
|
if (uCombinedSize == 0 || uCombinedSize > 0xFFFFFFFF)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint8* puCombined(static_cast<uint8*>(Malloc(uCombinedSize)));
|
|
pSource->m_pData = alias_cast<const char*>(puCombined);
|
|
pSource->m_uDataSize = (uint32)uCombinedSize;
|
|
|
|
kInputBuffer = SDXBCInputBuffer(puDXBC, puDXBC + uDXBCSize);
|
|
SDXBCOutputBuffer kOutputBuffer(puCombined, puCombined + uCombinedSize);
|
|
return DXBCCombineWithGLSL(kInputBuffer, kOutputBuffer, &kConversionOutput.m_kGLSLShader);
|
|
#else
|
|
#pragma error "Not implemented on this configuration"
|
|
#endif
|
|
}
|
|
|
|
#endif // !DXGL_INPUT_GLSL
|
|
|
|
bool InitializeShaderReflectionFromInput(SShaderReflection* pReflection, const void* pvInputData)
|
|
{
|
|
enum
|
|
{
|
|
SIZE_POSITION = 6
|
|
};
|
|
uint32 uInputDataSize(alias_cast<const uint32*>(pvInputData)[SIZE_POSITION]);
|
|
#if DXGL_INPUT_GLSL
|
|
return InitializeShaderReflection(pReflection, pvInputData, uInputDataSize);
|
|
#else
|
|
SShaderSource kTempShaderSource;
|
|
SGLSLConversionOutput kTempConversionOutput;
|
|
return
|
|
ConvertDXBCToGLSL(pvInputData, uInputDataSize, eSV_Normal, &kTempConversionOutput) &&
|
|
InitializeTranslatedShaderSource(&kTempShaderSource, pvInputData, uInputDataSize, kTempConversionOutput) &&
|
|
InitializeShaderReflection(pReflection, kTempShaderSource.m_pData, kTempShaderSource.m_uDataSize);
|
|
#endif
|
|
}
|
|
|
|
|
|
bool CompileShaderFromSources(SGLShader& shader, const GLchar* aszSources[], GLint aiSourceLengths[], uint32 uNumSources, GLenum eGLShaderType, bool isSeparableProgramsSupported)
|
|
{
|
|
shader.m_separableProgramsSupported = isSeparableProgramsSupported;
|
|
if (isSeparableProgramsSupported)
|
|
{
|
|
shader.m_uName = glCreateShaderProgramv(eGLShaderType, uNumSources, aszSources);
|
|
|
|
if (!shader.m_uName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!VerifyProgramStatus(shader.m_uName, GL_LINK_STATUS))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
shader.m_uName = glCreateShader(eGLShaderType);
|
|
if (!shader.m_uName)
|
|
{
|
|
return false;
|
|
}
|
|
glShaderSource(shader.m_uName, uNumSources, aszSources, aiSourceLengths);
|
|
glCompileShader(shader.m_uName);
|
|
|
|
if (!VerifyShaderStatus(shader.m_uName, GL_COMPILE_STATUS))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#if defined(glReleaseShaderCompiler)
|
|
DXGL_TODO("Check whether this is actually useful")
|
|
glReleaseShaderCompiler();
|
|
#endif //defined(glReleaseShaderCompiler)
|
|
}
|
|
return true;
|
|
}
|
|
|
|
SShader::SVersion& GetPipelineShaderVersion(const SPipelineConfiguration& kPipelineConfig, EShaderType eStage)
|
|
{
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
EShaderVersion eVersion(kPipelineConfig.m_aeShaderVersions[eStage]);
|
|
#else
|
|
EShaderVersion eVersion(eSV_Normal);
|
|
#endif
|
|
return kPipelineConfig.m_apShaders[eStage]->m_akVersions[eVersion];
|
|
}
|
|
|
|
bool FindShaderSymbolByType(const uint32* puSymbols, uint32 uNumSymbols, SYMBOL_TYPE eType, uint32* puID, uint32* puValue)
|
|
{
|
|
const uint32* puSymbolsEnd = puSymbols + uNumSymbols * 3;
|
|
for (const uint32* puSymbol = puSymbols; puSymbol != puSymbolsEnd; puSymbol += 3)
|
|
{
|
|
if ((SYMBOL_TYPE)puSymbol[0] == eType)
|
|
{
|
|
*puID = puSymbol[1];
|
|
*puValue = puSymbol[2];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FindShaderSymbolByTypeAndID(const uint32* puSymbols, uint32 uNumSymbols, SYMBOL_TYPE eType, uint32 uID, uint32* puValue)
|
|
{
|
|
const uint32* puSymbolsEnd = puSymbols + uNumSymbols * 3;
|
|
for (const uint32* puSymbol = puSymbols; puSymbol != puSymbolsEnd; puSymbol += 3)
|
|
{
|
|
if ((SYMBOL_TYPE)puSymbol[0] == eType && puSymbol[1] == uID)
|
|
{
|
|
*puValue = puSymbol[2];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <uint32 uMaxDigits>
|
|
uint32 WriteShaderDecimal(char* acOutput, uint32 uValue)
|
|
{
|
|
char acDigits[uMaxDigits];
|
|
char* pcDigit(acDigits + uMaxDigits - 1);
|
|
while (true)
|
|
{
|
|
uint32 uNext(uValue / 10);
|
|
uint32 uDigit(uValue % 10);
|
|
*pcDigit = '0' + uDigit;
|
|
if (uNext == 0 || pcDigit == acDigits)
|
|
{
|
|
break;
|
|
}
|
|
uValue = uNext;
|
|
--pcDigit;
|
|
}
|
|
uint32 uNumDigits((uint32)(acDigits + uMaxDigits - pcDigit));
|
|
memcpy(acOutput, pcDigit, uNumDigits);
|
|
return uNumDigits;
|
|
}
|
|
|
|
void BuildVersionString(SPipelineCompilationBuffer* pBuffer, CDevice* pDevice)
|
|
{
|
|
#if DXGL_REQUIRED_VERSION >= DXGL_VERSION_44
|
|
const char* szVersion = "#version 440\n";
|
|
// Workaround for AMD Catalyst - as of version 15.7.1 using "#version 440" causes std140 uniform buffers
|
|
// to have random layouts (see https://community.amd.com/thread/185272)
|
|
if (pDevice->GetAdapter()->m_eDriverVendor == RenderCapabilities::s_gpuVendorIdAMD)
|
|
{
|
|
szVersion = "#version 430\n";
|
|
}
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_43
|
|
const char* szVersion = "#version 430\n";
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_42
|
|
const char* szVersion = "#version 420\n";
|
|
#elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_41
|
|
const char* szVersion = "#version 410\n";
|
|
#elif DXGLES
|
|
uint32 glVersion = RenderCapabilities::GetDeviceGLVersion();
|
|
const char* szVersion;
|
|
if (glVersion == DXGLES_VERSION_30)
|
|
{
|
|
szVersion = "#version 300 es\n";
|
|
}
|
|
else
|
|
{
|
|
szVersion = "#version 310 es\n";
|
|
}
|
|
#else
|
|
#error "Shading language revision not defined for this GL version"
|
|
#endif
|
|
pBuffer->m_iVersionStringLength = min(strlen(szVersion), sizeof(pBuffer->m_acVersionString));
|
|
memcpy(pBuffer->m_acVersionString, szVersion, pBuffer->m_iVersionStringLength);
|
|
}
|
|
|
|
void BuildShaderImportHeader(SPipelineCompilationBuffer* pBuffer, const uint32* auImports, uint32 uNumImports, const SPipelineConfiguration& kConfiguration)
|
|
{
|
|
static const char acImportPrefix[] = "#define IMPORT_";
|
|
enum
|
|
{
|
|
IMPORT_INDEX_OFFSET = sizeof(acImportPrefix) - 1,
|
|
IMPORT_INDEX_MAX_DIGITS = 10,
|
|
IMPORT_VALUE_OFFSET = IMPORT_INDEX_OFFSET + IMPORT_INDEX_MAX_DIGITS + 1,
|
|
IMPORT_VALUE_MAX_DIGITS = 10,
|
|
IMPORT_NEWLINE_OFFSET = IMPORT_VALUE_OFFSET + IMPORT_VALUE_MAX_DIGITS,
|
|
IMPORT_STRIDE = IMPORT_NEWLINE_OFFSET + 1
|
|
};
|
|
|
|
if (pBuffer->m_uImportsHeaderCapacity < uNumImports)
|
|
{
|
|
pBuffer->m_acImportsHeader = static_cast<char*>(Realloc(pBuffer->m_acImportsHeader, IMPORT_STRIDE * uNumImports));
|
|
memset(pBuffer->m_acImportsHeader + IMPORT_STRIDE * pBuffer->m_uImportsHeaderCapacity, (int)' ', IMPORT_STRIDE * (uNumImports - pBuffer->m_uImportsHeaderCapacity));
|
|
for (uint32 uImport = pBuffer->m_uImportsHeaderCapacity; uImport < uNumImports; ++uImport)
|
|
{
|
|
char* acIter(pBuffer->m_acImportsHeader + IMPORT_STRIDE * uImport);
|
|
memcpy(acIter, acImportPrefix, IMPORT_INDEX_OFFSET);
|
|
WriteShaderDecimal<IMPORT_INDEX_MAX_DIGITS>(acIter + IMPORT_INDEX_OFFSET, uImport);
|
|
acIter[IMPORT_NEWLINE_OFFSET] = '\n';
|
|
}
|
|
pBuffer->m_uImportsHeaderCapacity = uNumImports;
|
|
}
|
|
|
|
pBuffer->m_uImportsBeginOffset = 0;
|
|
pBuffer->m_uImportsEndOffset = 0;
|
|
|
|
for (uint32 uImport = 0; uImport < uNumImports; ++uImport)
|
|
{
|
|
SYMBOL_TYPE eType((SYMBOL_TYPE)auImports[uImport * 3]);
|
|
uint32 uID(auImports[uImport * 3 + 1]);
|
|
uint32 uDefaultValue(auImports[uImport * 3 + 2]);
|
|
|
|
uint32 uReqValue = uDefaultValue;
|
|
switch (eType)
|
|
{
|
|
#if DXGL_SUPPORT_TESSELLATION
|
|
case SYMBOL_TESSELLATOR_PARTITIONING:
|
|
case SYMBOL_TESSELLATOR_OUTPUT_PRIMITIVE:
|
|
if (kConfiguration.m_apShaders[eST_TessControl])
|
|
{
|
|
const SShader::SVersion& kLinkVersion(GetPipelineShaderVersion(kConfiguration, eST_TessControl));
|
|
const uint32* auLinkExports(alias_cast<const uint32*>(kLinkVersion.m_kSource.m_pData + kLinkVersion.m_kReflection.m_uExportsOffset));
|
|
uint32 uNumLinkExports(kLinkVersion.m_kReflection.m_uExportsSize);
|
|
|
|
uint32 uExportID;
|
|
if (!FindShaderSymbolByType(auLinkExports, uNumLinkExports, eType, &uExportID, &uReqValue))
|
|
{
|
|
uReqValue = uDefaultValue;
|
|
}
|
|
}
|
|
break;
|
|
#endif //!DXGL_SUPPORT_TESSELLATION
|
|
case SYMBOL_INPUT_INTERPOLATION_MODE:
|
|
if (kConfiguration.m_apShaders[eST_Fragment])
|
|
{
|
|
const SShader::SVersion& kLinkVersion(GetPipelineShaderVersion(kConfiguration, eST_Fragment));
|
|
const uint32* auLinkExports(alias_cast<const uint32*>(kLinkVersion.m_kSource.m_pData + kLinkVersion.m_kReflection.m_uExportsOffset));
|
|
uint32 uNumLinkExports(kLinkVersion.m_kReflection.m_uExportsSize);
|
|
|
|
if (!FindShaderSymbolByTypeAndID(auLinkExports, uNumLinkExports, SYMBOL_INPUT_INTERPOLATION_MODE, uID, &uReqValue))
|
|
{
|
|
uReqValue = uDefaultValue;
|
|
}
|
|
}
|
|
break;
|
|
case SYMBOL_EMULATE_DEPTH_CLAMP:
|
|
#if DXGL_SUPPORT_DEPTH_CLAMP
|
|
uReqValue = 0;
|
|
#else
|
|
uReqValue = kConfiguration.m_bEmulateDepthClamp;
|
|
#endif
|
|
break;
|
|
default:
|
|
DXGL_ERROR("Unexpected shader import type");
|
|
break;
|
|
}
|
|
|
|
if (uReqValue != uDefaultValue || pBuffer->m_uImportsEndOffset > 0)
|
|
{
|
|
char* acIter(pBuffer->m_acImportsHeader + IMPORT_STRIDE * uImport + IMPORT_VALUE_OFFSET);
|
|
uint32 uNumDigits(WriteShaderDecimal<IMPORT_VALUE_MAX_DIGITS>(acIter, uReqValue));
|
|
if (uNumDigits < IMPORT_VALUE_MAX_DIGITS)
|
|
{
|
|
memset(acIter + uNumDigits, ' ', IMPORT_VALUE_MAX_DIGITS - uNumDigits);
|
|
}
|
|
if (pBuffer->m_uImportsEndOffset == 0)
|
|
{
|
|
pBuffer->m_uImportsBeginOffset = uImport * IMPORT_STRIDE;
|
|
}
|
|
pBuffer->m_uImportsEndOffset = (uImport + 1) * IMPORT_STRIDE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DXGL_DUMP_GLSL_SOURCES
|
|
|
|
void DumpShaderSources(const GLchar** aszSources, const GLint* aiSourceLengths, uint32 uNumSources, uint32 uHash, uint32 uVersion)
|
|
{
|
|
STraceFile kTraceFile;
|
|
char acBuffer[32];
|
|
if (uVersion == 0)
|
|
{
|
|
sprintf_s(acBuffer, "0x%08X.txt", uHash);
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(acBuffer, "0x%08X_%1d.txt", uHash, uVersion);
|
|
}
|
|
if (!kTraceFile.Open(acBuffer, false))
|
|
{
|
|
DXGL_ERROR("Could not open file \"%s\" for writing", acBuffer);
|
|
return;
|
|
}
|
|
for (uint32 uSource = 0; uSource < uNumSources; ++uSource)
|
|
{
|
|
kTraceFile.Write(aszSources[uSource], aiSourceLengths[uSource] - 1);
|
|
}
|
|
}
|
|
|
|
#endif //DXGL_DUMP_GLSL_SOURCES
|
|
|
|
bool CompilePipeline(SPipeline* pPipeline, SPipelineCompilationBuffer* pBuffer, CDevice* pDevice)
|
|
{
|
|
bool isSeparableProgramsSupported = pDevice->IsFeatureSupported(eF_SeparablePrograms);
|
|
if (isSeparableProgramsSupported)
|
|
{
|
|
glGenProgramPipelines(1, &pPipeline->m_uName);
|
|
}
|
|
else
|
|
{
|
|
pPipeline->m_uName = glCreateProgram();
|
|
}
|
|
|
|
for (uint32 uShader = 0; uShader < eST_NUM; ++uShader)
|
|
{
|
|
SShader* pShader(pPipeline->m_kConfiguration.m_apShaders[uShader]);
|
|
|
|
if (IsPipelineStageUsed(pPipeline->m_kConfiguration.m_eMode, (EShaderType)uShader) && pShader != NULL)
|
|
{
|
|
SShader::SVersion& kVersion(GetPipelineShaderVersion(pPipeline->m_kConfiguration, (EShaderType)uShader));
|
|
GLenum eGLShaderType;
|
|
if (!GetGLShaderType(eGLShaderType, (EShaderType)uShader))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (pBuffer->m_iVersionStringLength < 0)
|
|
{
|
|
BuildVersionString(pBuffer, pDevice);
|
|
}
|
|
|
|
uint32 uGLSLOffset(kVersion.m_kReflection.m_uGLSLSourceOffset);
|
|
uint32 uSymbolsOffset(kVersion.m_kReflection.m_uSymbolsOffset);
|
|
SSource kGLSLSource(kVersion.m_kSource.m_pData + uGLSLOffset, kVersion.m_kSource.m_uDataSize - uGLSLOffset);
|
|
const uint32* auImports(alias_cast<const uint32*>(kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uImportsOffset));
|
|
uint32 uNumImports(kVersion.m_kReflection.m_uImportsSize);
|
|
BuildShaderImportHeader(pBuffer, auImports, uNumImports, pPipeline->m_kConfiguration);
|
|
|
|
const GLchar* aszSources[4];
|
|
GLint aiSourceLengths[4];
|
|
uint32 uNumSources = 0;
|
|
|
|
aszSources[uNumSources] = pBuffer->m_acVersionString;
|
|
aiSourceLengths[uNumSources] = pBuffer->m_iVersionStringLength;
|
|
++uNumSources;
|
|
|
|
if (pBuffer->m_uImportsEndOffset > pBuffer->m_uImportsBeginOffset)
|
|
{
|
|
if (uSymbolsOffset > 0)
|
|
{
|
|
aszSources[uNumSources] = kGLSLSource.m_pData;
|
|
aiSourceLengths[uNumSources] = static_cast<GLint>(uSymbolsOffset);
|
|
++uNumSources;
|
|
}
|
|
|
|
aszSources[uNumSources] = pBuffer->m_acImportsHeader + pBuffer->m_uImportsBeginOffset;
|
|
aiSourceLengths[uNumSources] = static_cast<GLint>(pBuffer->m_uImportsEndOffset - pBuffer->m_uImportsBeginOffset);
|
|
++uNumSources;
|
|
|
|
aszSources[uNumSources] = kGLSLSource.m_pData + uSymbolsOffset;
|
|
aiSourceLengths[uNumSources] = static_cast<GLint>(kGLSLSource.m_uDataSize - 1 - uSymbolsOffset);
|
|
++uNumSources;
|
|
}
|
|
else
|
|
{
|
|
aszSources[uNumSources] = kGLSLSource.m_pData;
|
|
aiSourceLengths[uNumSources] = static_cast<GLint>(kGLSLSource.m_uDataSize - 1);
|
|
++uNumSources;
|
|
}
|
|
|
|
#if DXGL_DUMP_GLSL_SOURCES
|
|
DumpShaderSources(
|
|
aszSources + uFirstSource,
|
|
aiSourceLengths + uFirstSource,
|
|
uNumSources,
|
|
kVersion.m_kReflection.m_uInputHash,
|
|
pPipeline->m_kConfiguration.m_aeShaderVersions[uShader]);
|
|
#endif //DXGL_DUMP_GLSL_SOURCES
|
|
|
|
if (!CompileShaderFromSources(
|
|
pPipeline->m_akGLShaders[uShader],
|
|
aszSources,
|
|
aiSourceLengths,
|
|
uNumSources,
|
|
eGLShaderType,
|
|
isSeparableProgramsSupported))
|
|
{
|
|
DXGL_ERROR("Shader 0x%08X failed to compile", kVersion.m_kReflection.m_uInputHash);
|
|
return false;
|
|
}
|
|
|
|
if (isSeparableProgramsSupported)
|
|
{
|
|
GLbitfield uProgramStageBit(0);
|
|
if (!GetGLProgramStageBit(uProgramStageBit, pShader->m_eType))
|
|
{
|
|
return false;
|
|
}
|
|
glUseProgramStages(pPipeline->m_uName, uProgramStageBit, pPipeline->m_akGLShaders[uShader].m_uName);
|
|
}
|
|
else
|
|
{
|
|
glAttachShader(pPipeline->m_uName, pPipeline->m_akGLShaders[uShader].m_uName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isSeparableProgramsSupported)
|
|
{
|
|
glLinkProgram(pPipeline->m_uName);
|
|
|
|
if (!VerifyProgramStatus(pPipeline->m_uName, GL_LINK_STATUS))
|
|
{
|
|
CryLogAlways("Shader did not link properly !! ");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InitializeShader(SShader* pShader, const void* pvSourceData, size_t uSourceSize, const GLchar* szSourceOverride)
|
|
{
|
|
#if DXGL_INPUT_GLSL
|
|
SShader::SVersion& kVersion(pShader->m_akVersions[eSV_Normal]);
|
|
kVersion.m_kSource.SetData(reinterpret_cast<const char*>(pvSourceData), uSourceSize);
|
|
#else
|
|
SGLSLConversionOutput akConversionOutputs[eSV_NUM];
|
|
for (uint32 uVersion = 0; uVersion < eSV_NUM; ++uVersion)
|
|
{
|
|
SShader::SVersion& kVersion(pShader->m_akVersions[uVersion]);
|
|
|
|
if (!ConvertDXBCToGLSL(pvSourceData, uSourceSize, (EShaderVersion)uVersion, akConversionOutputs + uVersion) ||
|
|
!InitializeTranslatedShaderSource(&kVersion.m_kSource, pvSourceData, uSourceSize, akConversionOutputs[uVersion]))
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
uint32 uGLSLOffset;
|
|
if (!InitializeShaderReflection(&kVersion.m_kReflection, kVersion.m_kSource.m_pData, kVersion.m_kSource.m_uDataSize) ||
|
|
(uGLSLOffset = kVersion.m_kReflection.m_uGLSLSourceOffset) >= (uint32)uSourceSize)
|
|
{
|
|
DXGL_ERROR("Could not retrieve shader reflection data");
|
|
return false;
|
|
}
|
|
|
|
#if !DXGL_INPUT_GLSL
|
|
}
|
|
#endif
|
|
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
const ShaderInfo* pTracingInfo(&akConversionOutputs[eSV_Tracing].m_kGLSLShader.reflection);
|
|
uint32 uOffset = 0;
|
|
for (uint32 uStep = 0; uStep < pTracingInfo->ui32NumTraceSteps; ++uStep)
|
|
{
|
|
const StepTraceInfo* pStep(pTracingInfo->psTraceSteps + uStep);
|
|
for (uint32 uVariable = 0; uVariable < pStep->ui32NumVariables; ++uVariable)
|
|
{
|
|
pShader->m_kTraceIndex.m_kTraceVariables.push_back(pStep->psVariables[uVariable]);
|
|
}
|
|
pShader->m_kTraceIndex.m_kTraceStepOffsets.push_back(uOffset);
|
|
pShader->m_kTraceIndex.m_kTraceStepSizes.push_back(pStep->ui32NumVariables);
|
|
uOffset += pStep->ui32NumVariables;
|
|
}
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
|
|
return true;
|
|
}
|
|
|
|
GLuint GetProgramName(SPipeline* pPipeline, SShader* pShader)
|
|
{
|
|
if (!pPipeline->m_pContext->GetDevice()->IsFeatureSupported(eF_SeparablePrograms))
|
|
{
|
|
return pPipeline->m_uName;
|
|
}
|
|
|
|
return pPipeline->m_akGLShaders[pShader->m_eType].m_uName;
|
|
}
|
|
|
|
bool BindUniformBufferToUnit(GLuint uProgramName, uint32 uUnit, const char* szName, CContext* pContext)
|
|
{
|
|
GLuint uUniformBlockIndex(glGetUniformBlockIndex(uProgramName, szName));
|
|
if (uUniformBlockIndex == GL_INVALID_INDEX)
|
|
{
|
|
DXGL_WARNING("Could not find uniform buffer \"%s\" in program, probably optimized out by the GLSL compiler, ignoring binding", szName);
|
|
return true;
|
|
}
|
|
|
|
glUniformBlockBinding(uProgramName, uUniformBlockIndex, uUnit);
|
|
return true;
|
|
}
|
|
|
|
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS && !DXGLES
|
|
// GLES doesn't have the function glShaderStorageBlockBinding.
|
|
// Binding locations for shader storage is specified in the shader and can't be change.
|
|
bool BindStorageBufferToUnit(GLuint uProgramName, uint32 uUnit, const char* szName, CContext* pContext)
|
|
{
|
|
GLuint uStorageBlockIndex(glGetProgramResourceIndex(uProgramName, GL_SHADER_STORAGE_BLOCK, szName));
|
|
if (uStorageBlockIndex == GL_INVALID_INDEX)
|
|
{
|
|
DXGL_WARNING("Could not find storage buffer \"%s\" in program, probably optimized out by the GLSL compiler, ignoring binding", szName);
|
|
return true;
|
|
}
|
|
|
|
glShaderStorageBlockBinding(uProgramName, uStorageBlockIndex, uUnit);
|
|
return true;
|
|
}
|
|
#endif //DXGL_SUPPORT_SHADER_STORAGE_BLOCKS && !DXGLES
|
|
|
|
bool BindUniformToUnit(GLuint uProgramName, uint32 uUnit, const char* szName, CContext* pContext)
|
|
{
|
|
GLint iUniformBlockIndex(glGetUniformLocation(uProgramName, szName));
|
|
if (iUniformBlockIndex < 0)
|
|
{
|
|
DXGL_WARNING("Could not find uniform \"%s\" in program, probably optimized out by the GLSL compiler, ignoring binding", szName);
|
|
return true;
|
|
}
|
|
|
|
if (pContext->GetDevice()->IsFeatureSupported(eF_SeparablePrograms))
|
|
{
|
|
if (iUniformBlockIndex >= 0)
|
|
{
|
|
glProgramUniform1i(uProgramName, iUniformBlockIndex, uUnit);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAutoBindProgram kBindProgram(uProgramName);
|
|
if (iUniformBlockIndex >= 0)
|
|
{
|
|
glUniform1i(iUniformBlockIndex, uUnit);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
|
|
uint32 FindUnusedShaderStorageBufferUnit(SPipeline* pPipeline, CDevice* pDevice)
|
|
{
|
|
SBitMask<MAX_STORAGE_BUFFER_UNITS, SUnsafeBitMaskWord> kUsedUnitsMask;
|
|
|
|
SUnitMap* pStorageBufferMap = pPipeline->m_aspResourceUnitMaps[eRUT_StorageBuffer];
|
|
if (pStorageBufferMap == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const SUnitMap::SElement* pElementsBegin = pStorageBufferMap->m_akUnits;
|
|
const SUnitMap::SElement* pElementsEnd = pElementsBegin + pStorageBufferMap->m_uNumUnits;
|
|
for (const SUnitMap::SElement* pElement = pElementsBegin; pElement < pElementsEnd; ++pElement)
|
|
{
|
|
kUsedUnitsMask.Set(pElement->GetResourceUnit(), true);
|
|
}
|
|
|
|
uint32 uNumSupportedStorageSlots((uint32)pDevice->GetAdapter()->m_kCapabilities.m_akResourceUnits[eRUT_StorageBuffer].m_aiMaxTotal);
|
|
for (uint32 uSlot = 0; uSlot < uNumSupportedStorageSlots; ++uSlot)
|
|
{
|
|
if (!kUsedUnitsMask.Get(uSlot))
|
|
{
|
|
return uSlot;
|
|
}
|
|
}
|
|
|
|
return MAX_STORAGE_BUFFER_UNITS;
|
|
}
|
|
|
|
bool BindShaderTracingUnit(SPipeline* pPipeline, SShader* pShader, CDevice* pDevice)
|
|
{
|
|
uint32 uUnusedUnit = FindUnusedShaderStorageBufferUnit(pPipeline, pDevice);
|
|
if (uUnusedUnit == MAX_STORAGE_BUFFER_UNITS)
|
|
{
|
|
DXGL_ERROR("Could not find an extra storage buffer unit for shader tracing");
|
|
return false;
|
|
}
|
|
|
|
GLuint uProgramName(GetProgramName(pPipeline, pShader));
|
|
|
|
GLuint uStorageBlockIndex(glGetProgramResourceIndex(uProgramName, GL_SHADER_STORAGE_BLOCK, "Trace"));
|
|
if (uStorageBlockIndex == GL_INVALID_INDEX)
|
|
{
|
|
DXGL_ERROR("Could not find \"Trace\" shader storage block in program");
|
|
return false;
|
|
}
|
|
|
|
pPipeline->m_uTraceBufferUnit = uUnusedUnit;
|
|
glShaderStorageBlockBinding(uProgramName, uStorageBlockIndex, uUnusedUnit);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
|
|
struct SResourceIndexRange
|
|
{
|
|
uint32 m_uMin;
|
|
uint32 m_uMax;
|
|
|
|
SResourceIndexRange()
|
|
: m_uMin(0xFFFFFFFF)
|
|
, m_uMax(0)
|
|
{
|
|
}
|
|
|
|
bool Fits(const SIndexPartitionRange& kPartitionRange)
|
|
{
|
|
return m_uMin >= kPartitionRange.m_uFirstIn && m_uMax <= kPartitionRange.m_uFirstIn + kPartitionRange.m_uCount;
|
|
}
|
|
};
|
|
|
|
enum
|
|
{
|
|
ENCODED_SAMPLER_STRIDE = 3, ENCODED_RESOURCE_STRIDE = 2
|
|
};
|
|
|
|
template <uint32 (* DecodeFunc)(uint32), uint32 uStride>
|
|
void GetResourceIndexRange(SResourceIndexRange* pRange, const uint32* puResources, uint32 uNumResources)
|
|
{
|
|
pRange->m_uMin = 0xFFFFFFFF;
|
|
pRange->m_uMax = 0;
|
|
if (uNumResources > 0)
|
|
{
|
|
const uint32* puResourcesEnd = puResources + (uNumResources * uStride);
|
|
for (const uint32* puResource = puResources; puResource < puResourcesEnd; puResource += uStride)
|
|
{
|
|
uint32 uIndex = DecodeFunc(*puResource);
|
|
pRange->m_uMin = min(pRange->m_uMin, uIndex);
|
|
pRange->m_uMax = max(pRange->m_uMax, uIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SPipelineResourceRequirements
|
|
{
|
|
struct SResourceType
|
|
{
|
|
enum
|
|
{
|
|
INVALID_PARTITION_ID = 0xFFFFFFFF
|
|
};
|
|
|
|
uint32 m_uNumUnits;
|
|
uint32 m_uCompatiblePartitionID; // INVALID_PARTITION_ID if no partition is compatible
|
|
|
|
SResourceType()
|
|
: m_uNumUnits(0)
|
|
, m_uCompatiblePartitionID(0xFFFFFFFF)
|
|
{
|
|
}
|
|
};
|
|
|
|
SResourceType m_akTypes[eRUT_NUM];
|
|
};
|
|
|
|
void GetPipelineResourceRequirements(SPipelineResourceRequirements* pRequirements, const SPipeline* pPipeline, CContext* pContext)
|
|
{
|
|
DXGL_TODO("Instead of calculating the resource input ranges here, do it at translation-time and store them in the reflection");
|
|
SResourceIndexRange akInputRanges[eST_NUM][eRUT_NUM];
|
|
CDevice* pDevice = pContext->GetDevice();
|
|
|
|
for (uint32 uShader = 0; uShader < eST_NUM; ++uShader)
|
|
{
|
|
SShader* pShader(pPipeline->m_kConfiguration.m_apShaders[uShader]);
|
|
if (IsPipelineStageUsed(pPipeline->m_kConfiguration.m_eMode, (EShaderType)uShader) && pShader != NULL)
|
|
{
|
|
const SShader::SVersion& kVersion(GetPipelineShaderVersion(pPipeline->m_kConfiguration, (EShaderType)uShader));
|
|
const SShaderReflection& kReflection(kVersion.m_kReflection);
|
|
|
|
pRequirements->m_akTypes[eRUT_Texture].m_uNumUnits += kReflection.m_uNumSamplers;
|
|
GetResourceIndexRange<DXBC::DecodeTextureUnitIndex, ENCODED_SAMPLER_STRIDE>(
|
|
&akInputRanges[uShader][eRUT_Texture],
|
|
reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kReflection.m_uSamplersOffset),
|
|
kReflection.m_uNumSamplers);
|
|
|
|
pRequirements->m_akTypes[eRUT_UniformBuffer].m_uNumUnits += kReflection.m_uNumUniformBuffers;
|
|
GetResourceIndexRange<DXBC::DecodeResourceIndex, ENCODED_RESOURCE_STRIDE>(
|
|
&akInputRanges[uShader][eRUT_UniformBuffer],
|
|
reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kReflection.m_uUniformBuffersOffset),
|
|
kReflection.m_uNumUniformBuffers);
|
|
|
|
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
|
|
pRequirements->m_akTypes[eRUT_StorageBuffer].m_uNumUnits += kReflection.m_uNumStorageBuffers;
|
|
GetResourceIndexRange<DXBC::DecodeResourceIndex, ENCODED_RESOURCE_STRIDE>(
|
|
&akInputRanges[uShader][eRUT_StorageBuffer],
|
|
reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kReflection.m_uStorageBuffersOffset),
|
|
kReflection.m_uNumStorageBuffers);
|
|
#endif
|
|
|
|
#if DXGL_SUPPORT_SHADER_IMAGES
|
|
if (pDevice->IsFeatureSupported(eF_ShaderImages))
|
|
{
|
|
pRequirements->m_akTypes[eRUT_Image].m_uNumUnits += kReflection.m_uNumImages;
|
|
GetResourceIndexRange<DXBC::DecodeResourceIndex, ENCODED_RESOURCE_STRIDE>(
|
|
&akInputRanges[uShader][eRUT_Image],
|
|
reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kReflection.m_uImagesOffset),
|
|
kReflection.m_uNumImages);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
for (uint32 uResourceType = 0; uResourceType < eRUT_NUM; ++uResourceType)
|
|
{
|
|
uint32 uNumPartitions = pDevice->GetNumResourceUnitPartitions((EResourceUnitType)uResourceType);
|
|
for (uint32 uPartition = 0; uPartition < uNumPartitions; ++uPartition)
|
|
{
|
|
const SIndexPartition& kPartition(pDevice->GetResourceUnitPartition((EResourceUnitType)uResourceType, uPartition));
|
|
uint32 uStage;
|
|
for (uStage = 0; uStage < eST_NUM; ++uStage)
|
|
{
|
|
if (!akInputRanges[uStage][uResourceType].Fits(kPartition.m_akStages[uStage]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (uStage == eST_NUM)
|
|
{
|
|
pRequirements->m_akTypes[uResourceType].m_uCompatiblePartitionID = uPartition;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool InitializeTextureBindings(
|
|
SUnitMap* pMap,
|
|
uint32 uMapPosition,
|
|
const uint32* pSamplers,
|
|
uint32 uNumSamplers,
|
|
EShaderType eStage,
|
|
const char* szGLSL,
|
|
GLint iProgramName,
|
|
const SIndexPartition* pPartition,
|
|
CContext* pContext)
|
|
{
|
|
char acNameBuffer[MAX_REFLECT_STRING_LENGTH];
|
|
uint32 uNextTextureUnit = uMapPosition;
|
|
SUnitMap::SElement* pMapElementOut = pMap->m_akUnits + uMapPosition;
|
|
for (uint32 uElement = 0; uElement < uNumSamplers; ++uElement)
|
|
{
|
|
uint32 uSamplerField = pSamplers[uElement * 3 + 0];
|
|
uint32 uEmbeddedNormalName = pSamplers[uElement * 3 + 1];
|
|
uint32 uEmbeddedCompareName = pSamplers[uElement * 3 + 2];
|
|
|
|
uint32 uTextureIndex = DXBC::DecodeTextureIndex(uSamplerField);
|
|
uint32 uSamplerIndex = DXBC::DecodeSamplerIndex(uSamplerField);
|
|
uint32 uTextureUnitIndex = DXBC::DecodeTextureUnitIndex(uSamplerField);
|
|
bool bNormalSample = DXBC::DecodeNormalSample(uSamplerField);
|
|
bool bCompareSample = DXBC::DecodeCompareSample(uSamplerField);
|
|
|
|
uint32 uTextureSlot = TextureSlot(eStage, uTextureIndex);
|
|
uint32 uSamplerSlot = SamplerSlot(eStage, uSamplerIndex);
|
|
uint32 uTextureUnit = pPartition ? pPartition->m_akStages[eStage](uTextureUnitIndex) : uMapPosition + uElement;
|
|
|
|
bool bSample(bNormalSample || bCompareSample);
|
|
if (bSample)
|
|
{
|
|
*pMapElementOut = SUnitMap::SElement::TextureWithSampler(uTextureSlot, uSamplerSlot, uTextureUnit);
|
|
}
|
|
else
|
|
{
|
|
*pMapElementOut = SUnitMap::SElement::TextureWithoutSampler(uTextureSlot, uTextureUnit);
|
|
}
|
|
|
|
if (bNormalSample || !bSample) // Both normal sampling and texture loads use the "normal sampler name" field
|
|
{
|
|
if (!DXBC::GetEmbeddedName(acNameBuffer, szGLSL, uEmbeddedNormalName) ||
|
|
!BindUniformToUnit(iProgramName, uTextureUnit, acNameBuffer, pContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (bCompareSample)
|
|
{
|
|
if (!DXBC::GetEmbeddedName(acNameBuffer, szGLSL, uEmbeddedCompareName) ||
|
|
!BindUniformToUnit(iProgramName, uTextureUnit, acNameBuffer, pContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
++pMapElementOut;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool InitializeResourceBindings(
|
|
AZStd::function<bool(GLuint, uint32, const char*, CContext*)> pfBindResourceToUnit,
|
|
AZStd::function<uint32(EShaderType, uint32)> pfIndexToSlot,
|
|
SUnitMap* pMap,
|
|
uint32 uMapPosition,
|
|
const uint32* pResources,
|
|
uint32 uNumResources,
|
|
EShaderType eStage,
|
|
const char* szGLSL,
|
|
GLint iProgramName,
|
|
const SIndexPartition* pPartition,
|
|
CContext* pContext)
|
|
{
|
|
char acNameBuffer[MAX_REFLECT_STRING_LENGTH];
|
|
uint32 uNextResourceUnit = uMapPosition;
|
|
SUnitMap::SElement* pMapElementOut = pMap->m_akUnits + uMapPosition;
|
|
for (uint32 uElement = 0; uElement < uNumResources; ++uElement)
|
|
{
|
|
uint32 uResourceField = pResources[uElement * 2 + 0];
|
|
uint32 uResourceName = pResources[uElement * 2 + 1];
|
|
|
|
uint32 uResourceIndex = DXBC::DecodeResourceIndex(uResourceField);
|
|
|
|
uint32 uResourceSlot = pfIndexToSlot(eStage, uResourceIndex);
|
|
uint32 uResourceUnit;
|
|
if (pfBindResourceToUnit)
|
|
{
|
|
uResourceUnit = pPartition ? pPartition->m_akStages[eStage](uResourceIndex) : uMapPosition + uElement;
|
|
if (!DXBC::GetEmbeddedName(acNameBuffer, szGLSL, uResourceName) ||
|
|
!pfBindResourceToUnit(iProgramName, uResourceUnit, acNameBuffer, pContext))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Some resources, like Storage Buffers in OpenGLES, don't allow changing binding point.
|
|
// Because of this we have to use the binding that was set in the shader (we get the location from the reflection info).
|
|
uResourceUnit = uResourceIndex;
|
|
}
|
|
|
|
*pMapElementOut = SUnitMap::SElement::Resource(uResourceSlot, uResourceUnit);
|
|
++pMapElementOut;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool InitializePipelineResources(SPipeline* pPipeline, CContext* pContext)
|
|
{
|
|
SPipelineResourceRequirements kRequirements;
|
|
GetPipelineResourceRequirements(&kRequirements, pPipeline, pContext);
|
|
|
|
CDevice* pDevice = pContext->GetDevice();
|
|
|
|
const SIndexPartition* apUnitPartitions[eRUT_NUM];
|
|
SUnitMapPtr aspUnitMaps[eRUT_NUM];
|
|
uint32 auUnitMapPositions[eRUT_NUM];
|
|
for (uint32 uUnitType = 0; uUnitType < eRUT_NUM; ++uUnitType)
|
|
{
|
|
SPipelineResourceRequirements::SResourceType kType = kRequirements.m_akTypes[uUnitType];
|
|
if (kType.m_uCompatiblePartitionID == SPipelineResourceRequirements::SResourceType::INVALID_PARTITION_ID)
|
|
{
|
|
apUnitPartitions[uUnitType] = NULL;
|
|
}
|
|
else
|
|
{
|
|
apUnitPartitions[uUnitType] = &pDevice->GetResourceUnitPartition((EResourceUnitType)uUnitType, kType.m_uCompatiblePartitionID);
|
|
}
|
|
if (kType.m_uNumUnits > 0)
|
|
{
|
|
aspUnitMaps[uUnitType] = new SUnitMap(kType.m_uNumUnits);
|
|
}
|
|
auUnitMapPositions[uUnitType] = 0;
|
|
}
|
|
|
|
bool bSuccess = true;
|
|
for (uint32 uShader = 0; uShader < eST_NUM; ++uShader)
|
|
{
|
|
SShader* pShader(pPipeline->m_kConfiguration.m_apShaders[uShader]);
|
|
if (!IsPipelineStageUsed(pPipeline->m_kConfiguration.m_eMode, (EShaderType)uShader) || pShader == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GLuint uProgramName = GetProgramName(pPipeline, pShader);
|
|
const SShader::SVersion& kVersion(GetPipelineShaderVersion(pPipeline->m_kConfiguration, (EShaderType)uShader));
|
|
const char* szGLSL = kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uGLSLSourceOffset;
|
|
|
|
// Initialize texture unit map and bind texture units to shader uniforms
|
|
uint32 uNumSamplers(kVersion.m_kReflection.m_uNumSamplers);
|
|
if (uNumSamplers > 0)
|
|
{
|
|
const uint32* pSamplers(reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uSamplersOffset));
|
|
SUnitMap* pTextureUnitMap = aspUnitMaps[eRUT_Texture].get();
|
|
|
|
bSuccess &= InitializeTextureBindings(
|
|
pTextureUnitMap, auUnitMapPositions[eRUT_Texture],
|
|
pSamplers, uNumSamplers, (EShaderType)uShader,
|
|
szGLSL, uProgramName, apUnitPartitions[eRUT_Texture],
|
|
pContext);
|
|
|
|
auUnitMapPositions[eRUT_Texture] += uNumSamplers;
|
|
}
|
|
|
|
// Initialize uniform buffer unit map and bind uniform buffer units to shader uniform blocks
|
|
uint32 uNumUniformBuffers(kVersion.m_kReflection.m_uNumUniformBuffers);
|
|
if (uNumUniformBuffers > 0)
|
|
{
|
|
const uint32* pUniformBuffers(reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uUniformBuffersOffset));
|
|
SUnitMap* pUniformBufferMap = aspUnitMaps[eRUT_UniformBuffer].get();
|
|
|
|
bSuccess &= InitializeResourceBindings(&BindUniformBufferToUnit, &ConstantBufferSlot,
|
|
pUniformBufferMap, auUnitMapPositions[eRUT_UniformBuffer],
|
|
pUniformBuffers, uNumUniformBuffers, (EShaderType)uShader,
|
|
szGLSL, uProgramName, apUnitPartitions[eRUT_UniformBuffer],
|
|
pContext);
|
|
|
|
auUnitMapPositions[eRUT_UniformBuffer] += uNumUniformBuffers;
|
|
}
|
|
|
|
#if DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
|
|
// Initialize shader storage unit map and bind shader storage units to shader storage blocks
|
|
uint32 uNumStorageBuffers(kVersion.m_kReflection.m_uNumStorageBuffers);
|
|
if (uNumStorageBuffers > 0)
|
|
{
|
|
const uint32* pStorageBuffers(reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uStorageBuffersOffset));
|
|
SUnitMap* pStorageBufferMap = aspUnitMaps[eRUT_StorageBuffer].get();
|
|
|
|
#if DXGLES
|
|
// OpenGL ES doesn't support changing the binding point of storage buffers
|
|
auto bindStorageToUintFunc = nullptr;
|
|
#else
|
|
auto bindStorageToUintFunc = &BindStorageBufferToUnit;
|
|
#endif // DXGLES
|
|
bSuccess &= InitializeResourceBindings(bindStorageToUintFunc, &StorageBufferSlot,
|
|
pStorageBufferMap, auUnitMapPositions[eRUT_StorageBuffer],
|
|
pStorageBuffers, uNumStorageBuffers, (EShaderType)uShader,
|
|
szGLSL, uProgramName, apUnitPartitions[eRUT_StorageBuffer],
|
|
pContext);
|
|
|
|
auUnitMapPositions[eRUT_StorageBuffer] += uNumStorageBuffers;
|
|
}
|
|
#endif //DXGL_SUPPORT_SHADER_STORAGE_BLOCKS
|
|
|
|
#if DXGL_SUPPORT_SHADER_IMAGES
|
|
if (pDevice->IsFeatureSupported(eF_ShaderImages))
|
|
{
|
|
// Initialize image unit map and bind image units to shader uniforms
|
|
uint32 uNumImages(kVersion.m_kReflection.m_uNumImages);
|
|
if (uNumImages > 0)
|
|
{
|
|
const uint32* pImages(reinterpret_cast<const uint32*>(kVersion.m_kSource.m_pData + kVersion.m_kReflection.m_uImagesOffset));
|
|
SUnitMap* pImageMap = aspUnitMaps[eRUT_Image].get();
|
|
|
|
bSuccess &= InitializeResourceBindings(&BindUniformToUnit, &ImageSlot,
|
|
pImageMap, auUnitMapPositions[eRUT_Image],
|
|
pImages, uNumImages, (EShaderType)uShader,
|
|
szGLSL, uProgramName, apUnitPartitions[eRUT_Image],
|
|
pContext);
|
|
|
|
auUnitMapPositions[eRUT_Image] += uNumImages;
|
|
}
|
|
}
|
|
#endif //DXGL_SUPPORT_SHADER_IMAGES
|
|
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
if (pPipeline->m_kConfiguration.m_aeShaderVersions[uShader] == eSV_Tracing)
|
|
{
|
|
bSuccess &= BindShaderTracingUnit(pPipeline, pShader, pDevice);
|
|
}
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (uint32 uUnitType = 0; uUnitType < eRUT_NUM; ++uUnitType)
|
|
{
|
|
if (aspUnitMaps[uUnitType] != NULL)
|
|
{
|
|
pPipeline->m_aspResourceUnitMaps[uUnitType] = pContext->AllocateUnitMap(aspUnitMaps[uUnitType]);
|
|
bSuccess &= pPipeline->m_aspResourceUnitMaps[uUnitType] != NULL;
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
SPipelineConfiguration::SPipelineConfiguration()
|
|
: m_eMode(ePM_Graphics)
|
|
#if !DXGL_SUPPORT_DEPTH_CLAMP
|
|
, m_bEmulateDepthClamp(false)
|
|
#endif //!DXGL_SUPPORT_DEPTH_CLAMP
|
|
{
|
|
memset(m_apShaders, 0, sizeof(m_apShaders));
|
|
#if DXGL_ENABLE_SHADER_TRACING
|
|
memset(m_aeShaderVersions, 0, sizeof(m_aeShaderVersions));
|
|
#endif //DXGL_ENABLE_SHADER_TRACING
|
|
}
|
|
|
|
SPipelineCompilationBuffer::SPipelineCompilationBuffer()
|
|
: m_uImportsBeginOffset(0)
|
|
, m_uImportsEndOffset(0)
|
|
, m_uImportsHeaderCapacity(0)
|
|
, m_iVersionStringLength(-1)
|
|
, m_acImportsHeader(NULL)
|
|
{
|
|
memset(m_acVersionString, 0, sizeof(m_acVersionString));
|
|
}
|
|
|
|
SPipelineCompilationBuffer::~SPipelineCompilationBuffer()
|
|
{
|
|
if (m_acImportsHeader)
|
|
{
|
|
Free(m_acImportsHeader);
|
|
}
|
|
}
|
|
|
|
SUnitMap::SUnitMap(uint16 uNumUnits)
|
|
: m_uNumUnits(uNumUnits)
|
|
{
|
|
if (uNumUnits == 0)
|
|
{
|
|
m_akUnits = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_akUnits = new SElement[uNumUnits];
|
|
}
|
|
}
|
|
|
|
SUnitMap::SUnitMap(const SUnitMap& kOther)
|
|
: m_uNumUnits(kOther.m_uNumUnits)
|
|
{
|
|
if (m_uNumUnits == 0)
|
|
{
|
|
m_akUnits = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_akUnits = new SElement[m_uNumUnits];
|
|
memcpy(m_akUnits, kOther.m_akUnits, sizeof(SElement) * m_uNumUnits);
|
|
}
|
|
}
|
|
|
|
SUnitMap::~SUnitMap()
|
|
{
|
|
delete [] m_akUnits;
|
|
}
|
|
|
|
bool IsPipelineStageUsed(EPipelineMode eMode, EShaderType eType)
|
|
{
|
|
switch (eType)
|
|
{
|
|
case eST_Vertex:
|
|
case eST_Fragment:
|
|
#if DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
case eST_Geometry:
|
|
#endif //DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
#if DXGL_SUPPORT_TESSELLATION
|
|
case eST_TessControl:
|
|
case eST_TessEvaluation:
|
|
#endif //DXGL_SUPPORT_TESSELLATION
|
|
return eMode == ePM_Graphics;
|
|
#if DXGL_SUPPORT_COMPUTE
|
|
case eST_Compute:
|
|
return eMode == ePM_Compute;
|
|
#endif //DXGL_SUPPORT_COMPUTE
|
|
default:
|
|
DXGL_ERROR("Invalid shader type");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool GetGLShaderType(GLenum& eGLShaderType, EShaderType eType)
|
|
{
|
|
switch (eType)
|
|
{
|
|
case eST_Vertex:
|
|
eGLShaderType = GL_VERTEX_SHADER;
|
|
break;
|
|
case eST_Fragment:
|
|
eGLShaderType = GL_FRAGMENT_SHADER;
|
|
break;
|
|
#if DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
case eST_Geometry:
|
|
eGLShaderType = GL_GEOMETRY_SHADER;
|
|
break;
|
|
#endif //DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
#if DXGL_SUPPORT_TESSELLATION
|
|
case eST_TessControl:
|
|
eGLShaderType = GL_TESS_CONTROL_SHADER;
|
|
break;
|
|
case eST_TessEvaluation:
|
|
eGLShaderType = GL_TESS_EVALUATION_SHADER;
|
|
break;
|
|
#endif //DXGL_SUPPORT_TESSELLATION
|
|
#if DXGL_SUPPORT_COMPUTE
|
|
case eST_Compute:
|
|
eGLShaderType = GL_COMPUTE_SHADER;
|
|
break;
|
|
#endif //DXGL_SUPPORT_COMPUTE
|
|
default:
|
|
DXGL_ERROR("Invalid shader type");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GetGLProgramStageBit(GLbitfield& uProgramStageBit, EShaderType eType)
|
|
{
|
|
switch (eType)
|
|
{
|
|
case eST_Vertex:
|
|
uProgramStageBit = GL_VERTEX_SHADER_BIT;
|
|
break;
|
|
case eST_Fragment:
|
|
uProgramStageBit = GL_FRAGMENT_SHADER_BIT;
|
|
break;
|
|
#if DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
case eST_Geometry:
|
|
uProgramStageBit = GL_GEOMETRY_SHADER_BIT;
|
|
break;
|
|
#endif //DXGL_SUPPORT_GEOMETRY_SHADERS
|
|
#if DXGL_SUPPORT_TESSELLATION
|
|
case eST_TessControl:
|
|
uProgramStageBit = GL_TESS_CONTROL_SHADER_BIT;
|
|
break;
|
|
case eST_TessEvaluation:
|
|
uProgramStageBit = GL_TESS_EVALUATION_SHADER_BIT;
|
|
break;
|
|
#endif //DXGL_SUPPORT_TESSELLATION
|
|
#if DXGL_SUPPORT_COMPUTE
|
|
case eST_Compute:
|
|
uProgramStageBit = GL_COMPUTE_SHADER_BIT;
|
|
break;
|
|
#endif //DXGL_SUPPORT_COMPUTE
|
|
default:
|
|
DXGL_ERROR("Invalid shader type");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GetDataTypeSize(GLenum eDataType, GLuint& uSize)
|
|
{
|
|
DXGL_TODO("Verify that the sizes are correct according to the packing in layout structures");
|
|
switch (eDataType)
|
|
{
|
|
case GL_BYTE:
|
|
case GL_UNSIGNED_BYTE:
|
|
uSize = 1;
|
|
return true;
|
|
case GL_SHORT:
|
|
case GL_UNSIGNED_SHORT:
|
|
case GL_HALF_FLOAT:
|
|
uSize = 2;
|
|
return true;
|
|
case GL_INT:
|
|
case GL_UNSIGNED_INT:
|
|
case GL_INT_2_10_10_10_REV:
|
|
case GL_UNSIGNED_INT_2_10_10_10_REV:
|
|
case GL_FLOAT:
|
|
case GL_FIXED:
|
|
uSize = 4;
|
|
return true;
|
|
#if !DXGLES
|
|
// There is no GL_DOUBLE on OpenGL ES 3
|
|
case GL_DOUBLE:
|
|
uSize = 8;
|
|
return true;
|
|
#endif //!DXGLES
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool GetFormatAttributeDimension(const SGIFormatInfo* pFormatInfo, GLint& iDimensions)
|
|
{
|
|
switch (pFormatInfo->m_pTexture->m_eBaseFormat)
|
|
{
|
|
case GL_RGBA:
|
|
iDimensions = 4;
|
|
break;
|
|
case GL_RGB:
|
|
iDimensions = 3;
|
|
break;
|
|
case GL_RG:
|
|
iDimensions = 2;
|
|
break;
|
|
case GL_RED:
|
|
iDimensions = 1;
|
|
break;
|
|
#if (DXGLES && (GL_APPLE_texture_format_BGRA8888 || GL_IMG_read_format))
|
|
case GL_BGRA_IMG:
|
|
iDimensions = GL_BGRA_IMG; // Special value for packed reverse formats (A2B10G10R10*)
|
|
break;
|
|
#elif !DXGLES
|
|
case GL_BGRA:
|
|
iDimensions = GL_BGRA; // Special value for packed reverse formats (A2B10G10R10*)
|
|
break;
|
|
#endif
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GetFormatNormalized(const SUncompressedLayout* pLayout, GLboolean& bNormalized)
|
|
{
|
|
if (pLayout->m_eDepthType != eGICT_UNUSED || pLayout->m_eStencilType != eGICT_UNUSED) // As of D3D11.1 no format with depth or stencil channels supports buffers
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (pLayout->m_eColorType)
|
|
{
|
|
case eGICT_UNORM:
|
|
case eGICT_SNORM:
|
|
bNormalized = true;
|
|
break;
|
|
case eGICT_UINT:
|
|
case eGICT_SINT:
|
|
case eGICT_FLOAT:
|
|
bNormalized = false;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool PushInputLayoutAttribute(
|
|
SInputLayout& kLayout,
|
|
uint32 auSlotOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT],
|
|
const D3D11_INPUT_ELEMENT_DESC& kDesc,
|
|
uint32 uIndex,
|
|
bool bInteger,
|
|
const CDevice* pDevice)
|
|
{
|
|
SInputLayout::SAttributeParameters kParams;
|
|
SInputLayout::TAttributes& kSlotAttributes(kLayout.m_akSlotAttributes[kDesc.InputSlot]);
|
|
|
|
// The format must have texture and uncompressed layout information in order to determine
|
|
// the input layout
|
|
NCryOpenGL::EGIFormat eGIFormat(GetGIFormat(kDesc.Format));
|
|
const NCryOpenGL::SGIFormatInfo* pFormatInfo(NULL);
|
|
if (eGIFormat == eGIF_NUM || (pFormatInfo = (GetGIFormatInfo(eGIFormat))) == NULL ||
|
|
pFormatInfo->m_pTexture == NULL || pFormatInfo->m_pUncompressed == NULL)
|
|
{
|
|
DXGL_ERROR("Invalid DXGI format for vertex attribute");
|
|
return false;
|
|
}
|
|
|
|
kParams.m_uAttributeIndex = uIndex;
|
|
|
|
if (!GetFormatAttributeDimension(pFormatInfo, kParams.m_iDimension))
|
|
{
|
|
DXGL_ERROR("Invalid dimension for vertex attribute");
|
|
return false;
|
|
}
|
|
|
|
kParams.m_eType = pFormatInfo->m_pTexture->m_eDataType;
|
|
|
|
if (!GetFormatNormalized(pFormatInfo->m_pUncompressed, kParams.m_bNormalized))
|
|
{
|
|
DXGL_ERROR("Invalid layout for vertex attribute");
|
|
return false;
|
|
}
|
|
|
|
uint32& uSlotOffset(auSlotOffsets[kDesc.InputSlot]);
|
|
kParams.m_uPointerOffset = (kDesc.AlignedByteOffset == D3D11_APPEND_ALIGNED_ELEMENT) ? uSlotOffset : kDesc.AlignedByteOffset;
|
|
|
|
uint32 uSize;
|
|
if (!GetDataTypeSize(pFormatInfo->m_pTexture->m_eDataType, uSize))
|
|
{
|
|
DXGL_ERROR("Invalid data type for vertex attribute");
|
|
return false;
|
|
}
|
|
|
|
kParams.m_bInteger = bInteger;
|
|
kParams.m_uVertexAttribDivisor = kDesc.InstanceDataStepRate;
|
|
|
|
kSlotAttributes.push_back(kParams);
|
|
|
|
#if DXGL_SUPPORT_VERTEX_ATTRIB_BINDING
|
|
if (pDevice->IsFeatureSupported(eF_VertexAttribBinding))
|
|
{
|
|
SInputLayout::SAttributeFormats kParamsVAB;
|
|
SInputLayout::TAttributeFormats& kSlotAttributesVAB(kLayout.m_akVertexAttribFormats);
|
|
|
|
kParamsVAB.m_bInteger = kParams.m_bInteger;
|
|
kParamsVAB.m_iDimension = kParams.m_iDimension;
|
|
kParamsVAB.m_uAttributeIndex = kParams.m_uAttributeIndex;
|
|
kParamsVAB.m_bNormalized = kParams.m_bNormalized;
|
|
kParamsVAB.m_uPointerOffset = kParams.m_uPointerOffset;
|
|
kParamsVAB.m_eType = kParams.m_eType;
|
|
kParamsVAB.m_uVertexAttribDivisor = kParams.m_uVertexAttribDivisor;
|
|
|
|
kParamsVAB.m_uBindingIndex = kDesc.InputSlot;
|
|
kSlotAttributesVAB.push_back(kParamsVAB);
|
|
}
|
|
#endif //DXGL_SUPPORT_VERTEX_ATTRIB_BINDING
|
|
|
|
uSlotOffset += uSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
SInputLayoutPtr CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, uint32 uNumElements, const TShaderReflection& kReflection, const CDevice* pDevice)
|
|
{
|
|
SInputLayoutPtr spLayout(new SInputLayout());
|
|
uint32 auSlotOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
|
|
memset(auSlotOffsets, 0, sizeof(auSlotOffsets));
|
|
|
|
int attrMatchedNum = 0;
|
|
int reflectionAttrNum = 0;
|
|
|
|
//Calculate the number of attributes in the shader that does not start with 'SV_'
|
|
TShaderReflection::TParameters::const_iterator kInputSemanticIter(kReflection.m_kInputs.begin());
|
|
const TShaderReflection::TParameters::const_iterator kInputSemanticEnd(kReflection.m_kInputs.end());
|
|
while (kInputSemanticIter != kInputSemanticEnd)
|
|
{
|
|
if (strstr(kInputSemanticIter->m_kDesc.SemanticName, "SV_") == 0)
|
|
{
|
|
reflectionAttrNum++;
|
|
}
|
|
++kInputSemanticIter;
|
|
}
|
|
|
|
for (uint32 uElement = 0; uElement < uNumElements; ++uElement)
|
|
{
|
|
const D3D11_INPUT_ELEMENT_DESC& kDesc(pInputElementDescs[uElement]);
|
|
// Find a match within the input signatures of the shader reflection data
|
|
TShaderReflection::TParameters::const_iterator kInputSemanticIter(kReflection.m_kInputs.begin());
|
|
const TShaderReflection::TParameters::const_iterator kInputSemanticEnd(kReflection.m_kInputs.end());
|
|
while (kInputSemanticIter != kInputSemanticEnd)
|
|
{
|
|
if (kInputSemanticIter->m_kDesc.SemanticIndex == kDesc.SemanticIndex &&
|
|
strcmp(kInputSemanticIter->m_kDesc.SemanticName, kDesc.SemanticName) == 0)
|
|
{
|
|
bool bInteger;
|
|
switch (kInputSemanticIter->m_kDesc.ComponentType)
|
|
{
|
|
case D3D_REGISTER_COMPONENT_UNKNOWN:
|
|
assert(false);
|
|
case D3D_REGISTER_COMPONENT_FLOAT32:
|
|
bInteger = false;
|
|
break;
|
|
case D3D_REGISTER_COMPONENT_UINT32:
|
|
case D3D_REGISTER_COMPONENT_SINT32:
|
|
bInteger = true;
|
|
break;
|
|
default:
|
|
DXGL_ERROR("Invalid input signature component register type");
|
|
return NULL;
|
|
}
|
|
|
|
if (!PushInputLayoutAttribute(*spLayout, auSlotOffsets, kDesc, kInputSemanticIter->m_kDesc.Register, bInteger, pDevice))
|
|
{
|
|
DXGL_ERROR("Failed to Push Input Layout");
|
|
return NULL;
|
|
}
|
|
attrMatchedNum++;
|
|
break;
|
|
}
|
|
++kInputSemanticIter;
|
|
}
|
|
}
|
|
|
|
if (attrMatchedNum != reflectionAttrNum)
|
|
{
|
|
DXGL_ERROR("Shader input attributes count doesn not match with vertex format attributes count");
|
|
return NULL;
|
|
}
|
|
|
|
return spLayout;
|
|
}
|
|
|
|
#if defined(CODEGEN_FUNCPTR)
|
|
#define GL_ENTRY_POINT CODEGEN_FUNCPTR
|
|
#elif defined(GLAPIENTRY)
|
|
#define GL_ENTRY_POINT GLAPIENTRY
|
|
#elif defined(GL_APIENTRY)
|
|
#define GL_ENTRY_POINT GL_APIENTRY
|
|
#elif defined(APIENTRY)
|
|
#define GL_ENTRY_POINT APIENTRY
|
|
#else
|
|
#define GL_ENTRY_POINT
|
|
#endif
|
|
|
|
bool VerifyStatus(GLuint uName, GLenum eStatus, void (GL_ENTRY_POINT * fGetIV)(GLuint, GLenum, GLint*), void (GL_ENTRY_POINT * fGetInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*))
|
|
{
|
|
GLint iStatus;
|
|
fGetIV(uName, eStatus, &iStatus);
|
|
if (iStatus == GL_FALSE)
|
|
{
|
|
GLint iInfoLogLength;
|
|
fGetIV(uName, GL_INFO_LOG_LENGTH, &iInfoLogLength);
|
|
if (iInfoLogLength > 0)
|
|
{
|
|
GLchar* pBuffer = new GLchar[iInfoLogLength];
|
|
GLsizei iLength;
|
|
fGetInfoLog(uName, iInfoLogLength, &iLength, pBuffer);
|
|
if (iStatus == GL_FALSE)
|
|
{
|
|
DXGL_ERROR("%s", pBuffer);
|
|
}
|
|
delete [] pBuffer;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool VerifyShaderStatus(GLuint uShader, GLenum eStatus)
|
|
{
|
|
return VerifyStatus(uShader, eStatus, glGetShaderiv, glGetShaderInfoLog);
|
|
}
|
|
|
|
bool VerifyProgramStatus(GLuint uProgram, GLenum eStatus)
|
|
{
|
|
return VerifyStatus(uProgram, eStatus, glGetProgramiv, glGetProgramInfoLog);
|
|
}
|
|
|
|
bool VerifyProgramPipelineStatus(GLuint uPipelin, GLenum eStatus)
|
|
{
|
|
return VerifyStatus(uPipelin, eStatus, glGetProgramPipelineiv, glGetProgramPipelineInfoLog);
|
|
}
|
|
}
|