rhi: d3d: Use native resource binding mapping table when present
Newer versions of QShaderBaker will now use distinct, zero-based b, t+s, and u register spaces in the generated HLSL source. If this is the case, the native resource binding map (which so far we only used with Metal) contains the SPIR-V binding -> HLSL register binding mappings. This way we won't end up with invalid resource binding attempts (consider that e.g. D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT is only 16), just because, for example, a combined image sampler had a binding of 18 which then got blindly mapped to s18 and t18 in HLSL. Task-number: QTBUG-82472 Change-Id: I8bdcb5378634cf159f6367424582f9e9e5821c8e Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
parent
753e4d82be
commit
5bbc9986f9
@ -580,6 +580,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
|
||||
}
|
||||
}
|
||||
|
||||
static const int RBM_SUPPORTED_STAGES = 3;
|
||||
static const int RBM_VERTEX = 0;
|
||||
static const int RBM_FRAGMENT = 1;
|
||||
static const int RBM_COMPUTE = 2;
|
||||
|
||||
void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
|
||||
int dynamicOffsetCount,
|
||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
||||
@ -667,8 +672,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
||||
}
|
||||
}
|
||||
|
||||
if (srbUpdate)
|
||||
updateShaderResourceBindings(srbD);
|
||||
if (srbUpdate) {
|
||||
const QShader::NativeResourceBindingMap *resBindMaps[RBM_SUPPORTED_STAGES];
|
||||
memset(resBindMaps, 0, sizeof(resBindMaps));
|
||||
if (gfxPsD) {
|
||||
resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap;
|
||||
resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap;
|
||||
} else {
|
||||
resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap;
|
||||
}
|
||||
updateShaderResourceBindings(srbD, resBindMaps);
|
||||
}
|
||||
|
||||
const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
|
||||
const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
|
||||
@ -1774,7 +1788,26 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||
cbD->commands.append(cmd);
|
||||
}
|
||||
|
||||
void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
static inline QPair<int, int> mapBinding(int binding,
|
||||
int stageIndex,
|
||||
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
|
||||
{
|
||||
const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
|
||||
if (!map || map->isEmpty())
|
||||
return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then
|
||||
|
||||
auto it = map->constFind(binding);
|
||||
if (it != map->cend())
|
||||
return *it;
|
||||
|
||||
// Hitting this path is normal too. It is not given that the resource is
|
||||
// present in the shaders for all the stages specified by the visibility
|
||||
// mask in the QRhiShaderResourceBinding.
|
||||
return { -1, -1 };
|
||||
}
|
||||
|
||||
void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
|
||||
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
|
||||
{
|
||||
srbD->vsubufs.clear();
|
||||
srbD->vsubufoffsets.clear();
|
||||
@ -1799,6 +1832,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
|
||||
srbD->csUAVs.clear();
|
||||
|
||||
struct Stage {
|
||||
struct Buffer {
|
||||
int breg; // b0, b1, ...
|
||||
ID3D11Buffer *buffer;
|
||||
uint offsetInConstants;
|
||||
uint sizeInConstants;
|
||||
};
|
||||
struct Texture {
|
||||
int treg; // t0, t1, ...
|
||||
ID3D11ShaderResourceView *srv;
|
||||
};
|
||||
struct Sampler {
|
||||
int sreg; // s0, s1, ...
|
||||
ID3D11SamplerState *sampler;
|
||||
};
|
||||
struct Uav {
|
||||
int ureg;
|
||||
ID3D11UnorderedAccessView *uav;
|
||||
};
|
||||
QVarLengthArray<Buffer, 8> buffers;
|
||||
QVarLengthArray<Texture, 8> textures;
|
||||
QVarLengthArray<Sampler, 8> samplers;
|
||||
QVarLengthArray<Uav, 8> uavs;
|
||||
} res[RBM_SUPPORTED_STAGES];
|
||||
|
||||
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
|
||||
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
|
||||
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
|
||||
@ -1818,26 +1876,24 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
// (ByteWidth) is always a multiple of 256.
|
||||
const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16);
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||
srbD->vsubufs.feed(b->binding, bufD->buffer);
|
||||
srbD->vsubufoffsets.feed(b->binding, offsetInConstants);
|
||||
srbD->vsubufsizes.feed(b->binding, sizeInConstants);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0)
|
||||
res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
|
||||
}
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||
srbD->fsubufs.feed(b->binding, bufD->buffer);
|
||||
srbD->fsubufoffsets.feed(b->binding, offsetInConstants);
|
||||
srbD->fsubufsizes.feed(b->binding, sizeInConstants);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0)
|
||||
res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
|
||||
}
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||
srbD->csubufs.feed(b->binding, bufD->buffer);
|
||||
srbD->csubufoffsets.feed(b->binding, offsetInConstants);
|
||||
srbD->csubufsizes.feed(b->binding, sizeInConstants);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0)
|
||||
res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QRhiShaderResourceBinding::SampledTexture:
|
||||
{
|
||||
// A sampler with binding N is mapped to a HLSL sampler and texture
|
||||
// with registers sN and tN by SPIRV-Cross.
|
||||
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
|
||||
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
|
||||
bd.stex.texId = texD->m_id;
|
||||
@ -1845,16 +1901,25 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
bd.stex.samplerId = samplerD->m_id;
|
||||
bd.stex.samplerGeneration = samplerD->generation;
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||
srbD->vssamplers.feed(b->binding, samplerD->samplerState);
|
||||
srbD->vsshaderresources.feed(b->binding, texD->srv);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
|
||||
res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv });
|
||||
res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState });
|
||||
}
|
||||
}
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||
srbD->fssamplers.feed(b->binding, samplerD->samplerState);
|
||||
srbD->fsshaderresources.feed(b->binding, texD->srv);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
|
||||
res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv });
|
||||
res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState });
|
||||
}
|
||||
}
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||
srbD->cssamplers.feed(b->binding, samplerD->samplerState);
|
||||
srbD->csshaderresources.feed(b->binding, texD->srv);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
|
||||
res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv });
|
||||
res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState });
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1866,9 +1931,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
bd.simage.id = texD->m_id;
|
||||
bd.simage.generation = texD->generation;
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||
ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
|
||||
if (uav)
|
||||
srbD->csUAVs.feed(b->binding, uav);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0) {
|
||||
ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
|
||||
if (uav)
|
||||
res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
|
||||
}
|
||||
} else {
|
||||
qWarning("Unordered access only supported at compute stage");
|
||||
}
|
||||
@ -1882,9 +1950,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
bd.sbuf.id = bufD->m_id;
|
||||
bd.sbuf.generation = bufD->generation;
|
||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||
ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView();
|
||||
if (uav)
|
||||
srbD->csUAVs.feed(b->binding, uav);
|
||||
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
|
||||
if (nativeBinding.first >= 0) {
|
||||
ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView();
|
||||
if (uav)
|
||||
res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
|
||||
}
|
||||
} else {
|
||||
qWarning("Unordered access only supported at compute stage");
|
||||
}
|
||||
@ -1896,27 +1967,75 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||
}
|
||||
}
|
||||
|
||||
// QRhiBatchedBindings works with the native bindings and expects
|
||||
// sorted input. The pre-sorted QRhiShaderResourceBinding list (based
|
||||
// on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
|
||||
// have to sort here every time.
|
||||
for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) {
|
||||
std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
|
||||
return a.breg < b.breg;
|
||||
});
|
||||
std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
|
||||
return a.treg < b.treg;
|
||||
});
|
||||
std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
|
||||
return a.sreg < b.sreg;
|
||||
});
|
||||
std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) {
|
||||
return a.ureg < b.ureg;
|
||||
});
|
||||
}
|
||||
|
||||
for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) {
|
||||
srbD->vsubufs.feed(buf.breg, buf.buffer);
|
||||
srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants);
|
||||
srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants);
|
||||
}
|
||||
srbD->vsubufs.finish();
|
||||
srbD->vsubufoffsets.finish();
|
||||
srbD->vsubufsizes.finish();
|
||||
|
||||
for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) {
|
||||
srbD->fsubufs.feed(buf.breg, buf.buffer);
|
||||
srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants);
|
||||
srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants);
|
||||
}
|
||||
srbD->fsubufs.finish();
|
||||
srbD->fsubufoffsets.finish();
|
||||
srbD->fsubufsizes.finish();
|
||||
|
||||
for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) {
|
||||
srbD->csubufs.feed(buf.breg, buf.buffer);
|
||||
srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants);
|
||||
srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants);
|
||||
}
|
||||
srbD->csubufs.finish();
|
||||
srbD->csubufoffsets.finish();
|
||||
srbD->csubufsizes.finish();
|
||||
|
||||
for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures))
|
||||
srbD->vsshaderresources.feed(t.treg, t.srv);
|
||||
for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers))
|
||||
srbD->vssamplers.feed(s.sreg, s.sampler);
|
||||
srbD->vssamplers.finish();
|
||||
srbD->vsshaderresources.finish();
|
||||
|
||||
for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures))
|
||||
srbD->fsshaderresources.feed(t.treg, t.srv);
|
||||
for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers))
|
||||
srbD->fssamplers.feed(s.sreg, s.sampler);
|
||||
srbD->fssamplers.finish();
|
||||
srbD->fsshaderresources.finish();
|
||||
|
||||
for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures))
|
||||
srbD->csshaderresources.feed(t.treg, t.srv);
|
||||
for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers))
|
||||
srbD->cssamplers.feed(s.sreg, s.sampler);
|
||||
srbD->cssamplers.finish();
|
||||
srbD->csshaderresources.finish();
|
||||
|
||||
for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs))
|
||||
srbD->csUAVs.feed(u.ureg, u.uav);
|
||||
srbD->csUAVs.finish();
|
||||
}
|
||||
|
||||
@ -2205,8 +2324,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
|
||||
case QD3D11CommandBuffer::Command::BindGraphicsPipeline:
|
||||
{
|
||||
QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps;
|
||||
context->VSSetShader(psD->vs, nullptr, 0);
|
||||
context->PSSetShader(psD->fs, nullptr, 0);
|
||||
context->VSSetShader(psD->vs.shader, nullptr, 0);
|
||||
context->PSSetShader(psD->fs.shader, nullptr, 0);
|
||||
context->IASetPrimitiveTopology(psD->d3dTopology);
|
||||
context->IASetInputLayout(psD->inputLayout);
|
||||
context->OMSetDepthStencilState(psD->dsState, stencilRef);
|
||||
@ -2281,7 +2400,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
|
||||
annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
|
||||
break;
|
||||
case QD3D11CommandBuffer::Command::BindComputePipeline:
|
||||
context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0);
|
||||
context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0);
|
||||
break;
|
||||
case QD3D11CommandBuffer::Command::Dispatch:
|
||||
context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
|
||||
@ -3137,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings()
|
||||
void QD3D11ShaderResourceBindings::release()
|
||||
{
|
||||
sortedBindings.clear();
|
||||
boundResourceData.clear();
|
||||
}
|
||||
|
||||
bool QD3D11ShaderResourceBindings::build()
|
||||
@ -3153,8 +3273,8 @@ bool QD3D11ShaderResourceBindings::build()
|
||||
|
||||
boundResourceData.resize(sortedBindings.count());
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
rhiD->updateShaderResourceBindings(this);
|
||||
for (BoundResourceData &bd : boundResourceData)
|
||||
memset(&bd, 0, sizeof(BoundResourceData));
|
||||
|
||||
generation += 1;
|
||||
return true;
|
||||
@ -3195,15 +3315,17 @@ void QD3D11GraphicsPipeline::release()
|
||||
rastState = nullptr;
|
||||
}
|
||||
|
||||
if (vs) {
|
||||
vs->Release();
|
||||
vs = nullptr;
|
||||
if (vs.shader) {
|
||||
vs.shader->Release();
|
||||
vs.shader = nullptr;
|
||||
}
|
||||
vs.nativeResourceBindingMap.clear();
|
||||
|
||||
if (fs) {
|
||||
fs->Release();
|
||||
fs = nullptr;
|
||||
if (fs.shader) {
|
||||
fs.shader->Release();
|
||||
fs.shader = nullptr;
|
||||
}
|
||||
fs.nativeResourceBindingMap.clear();
|
||||
|
||||
rhiD->unregisterResource(this);
|
||||
}
|
||||
@ -3405,13 +3527,14 @@ static pD3DCompile resolveD3DCompile()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error)
|
||||
static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey)
|
||||
{
|
||||
QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant });
|
||||
if (!dxbc.shader().isEmpty())
|
||||
return dxbc.shader();
|
||||
|
||||
QShaderCode hlslSource = shader.shader({ QShader::HlslShader, 50, shaderVariant });
|
||||
const QShaderKey key = { QShader::HlslShader, 50, shaderVariant };
|
||||
QShaderCode hlslSource = shader.shader(key);
|
||||
if (hlslSource.shader().isEmpty()) {
|
||||
qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
|
||||
return QByteArray();
|
||||
@ -3463,6 +3586,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (usedShaderKey)
|
||||
*usedShaderKey = key;
|
||||
|
||||
QByteArray result;
|
||||
result.resize(int(bytecode->GetBufferSize()));
|
||||
memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
|
||||
@ -3554,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build()
|
||||
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
|
||||
switch (shaderStage.type()) {
|
||||
case QRhiShaderStage::Vertex:
|
||||
vs = static_cast<ID3D11VertexShader *>(cacheIt->s);
|
||||
vs->AddRef();
|
||||
vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s);
|
||||
vs.shader->AddRef();
|
||||
vsByteCode = cacheIt->bytecode;
|
||||
vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
|
||||
break;
|
||||
case QRhiShaderStage::Fragment:
|
||||
fs = static_cast<ID3D11PixelShader *>(cacheIt->s);
|
||||
fs->AddRef();
|
||||
fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
|
||||
fs.shader->AddRef();
|
||||
fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
QString error;
|
||||
const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
|
||||
QShaderKey shaderKey;
|
||||
const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error, &shaderKey);
|
||||
if (bytecode.isEmpty()) {
|
||||
qWarning("HLSL shader compilation failed: %s", qPrintable(error));
|
||||
return false;
|
||||
@ -3580,23 +3709,27 @@ bool QD3D11GraphicsPipeline::build()
|
||||
|
||||
switch (shaderStage.type()) {
|
||||
case QRhiShaderStage::Vertex:
|
||||
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs);
|
||||
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
|
||||
return false;
|
||||
}
|
||||
vsByteCode = bytecode;
|
||||
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode));
|
||||
vs->AddRef();
|
||||
if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
|
||||
vs.nativeResourceBindingMap = *map;
|
||||
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
|
||||
vs.shader->AddRef();
|
||||
break;
|
||||
case QRhiShaderStage::Fragment:
|
||||
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs);
|
||||
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
|
||||
return false;
|
||||
}
|
||||
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode));
|
||||
fs->AddRef();
|
||||
if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
|
||||
fs.nativeResourceBindingMap = *map;
|
||||
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
|
||||
fs.shader->AddRef();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -3655,46 +3788,52 @@ void QD3D11ComputePipeline::release()
|
||||
{
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
|
||||
if (!cs)
|
||||
if (!cs.shader)
|
||||
return;
|
||||
|
||||
cs->Release();
|
||||
cs = nullptr;
|
||||
cs.shader->Release();
|
||||
cs.shader = nullptr;
|
||||
cs.nativeResourceBindingMap.clear();
|
||||
|
||||
rhiD->unregisterResource(this);
|
||||
}
|
||||
|
||||
bool QD3D11ComputePipeline::build()
|
||||
{
|
||||
if (cs)
|
||||
if (cs.shader)
|
||||
release();
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
|
||||
auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
|
||||
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
|
||||
cs = static_cast<ID3D11ComputeShader *>(cacheIt->s);
|
||||
cs.shader = static_cast<ID3D11ComputeShader *>(cacheIt->s);
|
||||
cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
|
||||
} else {
|
||||
QString error;
|
||||
const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
|
||||
QShaderKey shaderKey;
|
||||
const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error, &shaderKey);
|
||||
if (bytecode.isEmpty()) {
|
||||
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs);
|
||||
HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey))
|
||||
cs.nativeResourceBindingMap = *map;
|
||||
|
||||
if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
|
||||
rhiD->clearShaderCache();
|
||||
|
||||
rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode));
|
||||
rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap));
|
||||
}
|
||||
|
||||
cs->AddRef();
|
||||
cs.shader->AddRef();
|
||||
|
||||
generation += 1;
|
||||
rhiD->registerResource(this);
|
||||
|
@ -270,8 +270,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
|
||||
|
||||
ID3D11DepthStencilState *dsState = nullptr;
|
||||
ID3D11BlendState *blendState = nullptr;
|
||||
ID3D11VertexShader *vs = nullptr;
|
||||
ID3D11PixelShader *fs = nullptr;
|
||||
struct {
|
||||
ID3D11VertexShader *shader = nullptr;
|
||||
QShader::NativeResourceBindingMap nativeResourceBindingMap;
|
||||
} vs;
|
||||
struct {
|
||||
ID3D11PixelShader *shader = nullptr;
|
||||
QShader::NativeResourceBindingMap nativeResourceBindingMap;
|
||||
} fs;
|
||||
ID3D11InputLayout *inputLayout = nullptr;
|
||||
D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
ID3D11RasterizerState *rastState = nullptr;
|
||||
@ -286,7 +292,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline
|
||||
void release() override;
|
||||
bool build() override;
|
||||
|
||||
ID3D11ComputeShader *cs = nullptr;
|
||||
struct {
|
||||
ID3D11ComputeShader *shader = nullptr;
|
||||
QShader::NativeResourceBindingMap nativeResourceBindingMap;
|
||||
} cs;
|
||||
uint generation = 0;
|
||||
friend class QRhiD3D11;
|
||||
};
|
||||
@ -642,7 +651,8 @@ public:
|
||||
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
|
||||
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
|
||||
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
|
||||
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD);
|
||||
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
|
||||
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
|
||||
void executeBufferHostWrites(QD3D11Buffer *bufD);
|
||||
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
|
||||
const uint *dynOfsPairs, int dynOfsPairCount,
|
||||
@ -701,9 +711,11 @@ public:
|
||||
|
||||
struct Shader {
|
||||
Shader() = default;
|
||||
Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { }
|
||||
Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
|
||||
: s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
|
||||
IUnknown *s;
|
||||
QByteArray bytecode;
|
||||
QShader::NativeResourceBindingMap nativeResourceBindingMap;
|
||||
};
|
||||
QHash<QRhiShaderStage, Shader> m_shaderCache;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user