From 5eacc974c705d3cf0041847a5dac5890cda200d3 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 12 Aug 2022 14:23:44 +0200 Subject: [PATCH] rhi: d3d11: Enable tessellation and geometry with some caveats The caveat being having to manually create HLSL versions of the hull, domain, and geometry shaders in parallel with the Vulkan GLSL ones, while keeping the interfaces intact (stage inputs and outputs, cbuffer layouts, binding points/registers). This is not always trivial but typically doable in not very complicated case after inspecting the SPIRV-Cross-generated vertex/fragment code in the .qsb files. Once written, the HLSL files can be injected into a .qsb file with qsb -r. or the corresponding CMake syntax. Conceptually this is no different from how samplerExternalOES support is implemented for Multimedia. (there the problem is that the shaders cannot be compiled to SPIR-V to begin with, here it is that we cannot translate from SPIR-V, but in the end the workaround for both problems is effectively the same) The manual tests demonstrate this, both the tessellation and geometry apps work now with D3D out of the box. On the bright side, the implementation here in the the D3D backend of QRhi does not need to know about how the shaders got there in the QShader. So none of the implementation is dependent on this manual process. If some day qsb would start translating to these kind of shaders as well, it would all still work as-is. Change-Id: I32d9ab94e00174e4bd5b59ac814dfedef9f93ad1 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhi.cpp | 30 +- src/gui/rhi/qrhid3d11.cpp | 545 ++++++++++-------- src/gui/rhi/qrhid3d11_p_p.h | 98 +++- .../rhi/geometryshader/buildshaders.bat | 5 +- tests/manual/rhi/geometryshader/test.frag.qsb | Bin 345 -> 456 bytes tests/manual/rhi/geometryshader/test.geom.qsb | Bin 991 -> 1222 bytes tests/manual/rhi/geometryshader/test.vert.qsb | Bin 429 -> 591 bytes .../manual/rhi/geometryshader/test_geom.hlsl | 26 + .../manual/rhi/tessellation/buildshaders.bat | 6 +- tests/manual/rhi/tessellation/test.frag.qsb | Bin 425 -> 581 bytes tests/manual/rhi/tessellation/test.tesc.qsb | Bin 840 -> 1202 bytes tests/manual/rhi/tessellation/test.tese.qsb | Bin 1174 -> 1522 bytes tests/manual/rhi/tessellation/test.vert.qsb | Bin 527 -> 714 bytes .../manual/rhi/tessellation/test_domain.hlsl | 38 ++ tests/manual/rhi/tessellation/test_hull.hlsl | 40 ++ 15 files changed, 489 insertions(+), 299 deletions(-) create mode 100644 tests/manual/rhi/geometryshader/test_geom.hlsl create mode 100644 tests/manual/rhi/tessellation/test_domain.hlsl create mode 100644 tests/manual/rhi/tessellation/test_hull.hlsl diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 94367fbcd5..3cc6a8da83 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -677,23 +677,27 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") can be set via \l{QRhiGraphicsPipeline::setPatchControlPointCount()}{setPatchControlPointCount()}, and shaders for tessellation control and evaluation can be specified in the - QRhiShaderStage list. \b{Tessellation is considered an experimental feature - in QRhi and can only be expected to be supported with Vulkan, OpenGL and - OpenGL ES for the time being}, assuming the implementation reports it as - supported at run time. Tessellation shaders have portability issues between - APIs (for example, translating GLSL/SPIR-V to HLSL is problematic due to - the way hull shaders are structured, whereas Metal uses a somewhat - different tessellation pipeline than others), and therefore no guarantees - can be given for a universal solution for now. + QRhiShaderStage list. Tessellation is considered an experimental feature in + QRhi and can only be expected to be supported with Vulkan, OpenGL (ES), and + Direct 3D, assuming the implementation reports it as supported at run time. + Tessellation shaders have portability issues between APIs (for example, + translating GLSL/SPIR-V to HLSL is problematic due to the way hull shaders + are structured, whereas Metal uses a somewhat different tessellation + pipeline than others), and therefore no guarantees can be given for a + universal solution for now. (for Direct 3D in particular, handwritten HLSL + hull and domain shaders must be injected into each QShader since qsb cannot + generate these from SPIR-V) \value GeometryShader Indicates that the geometry shader stage is supported. When supported, a geometry shader can be specified in the - QRhiShaderStage list. \b{Geometry Shaders are considered an experimental + QRhiShaderStage list. Geometry Shaders are considered an experimental feature in QRhi and can only be expected to be supported with Vulkan, - OpenGL (3.2+) and OpenGL ES (3.2+) for the time being}, assuming the - implementation reports it as supported at run time. Geometry shaders have - portability issues between APIs, and therefore no guarantees can be given - for a universal solution for now. + Direct 3D, OpenGL (3.2+) and OpenGL ES (3.2+), assuming the implementation + reports it as supported at run time. Geometry shaders have portability + issues between APIs, and therefore no guarantees can be given for a + universal solution for now. (for Direct 3D in particular, a handwritten + HLSL geometry shader must be injected into each QShader since qsb cannot + generate this from SPIR-V) \value TextureArrayRange Indicates that for \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 7c45b9c561..2a69474433 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -537,9 +537,9 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const case QRhi::TextureArrays: return true; case QRhi::Tessellation: - return false; + return true; case QRhi::GeometryShader: - return false; + return true; case QRhi::TextureArrayRange: return true; case QRhi::NonFillPolygonMode: @@ -840,10 +840,13 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline } } -static const int RBM_SUPPORTED_STAGES = 3; +static const int RBM_SUPPORTED_STAGES = 6; static const int RBM_VERTEX = 0; -static const int RBM_FRAGMENT = 1; -static const int RBM_COMPUTE = 2; +static const int RBM_HULL = 1; +static const int RBM_DOMAIN = 2; +static const int RBM_GEOMETRY = 3; +static const int RBM_FRAGMENT = 4; +static const int RBM_COMPUTE = 5; void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, @@ -952,6 +955,9 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind memset(resBindMaps, 0, sizeof(resBindMaps)); if (gfxPsD) { resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap; + resBindMaps[RBM_HULL] = &gfxPsD->hs.nativeResourceBindingMap; + resBindMaps[RBM_DOMAIN] = &gfxPsD->ds.nativeResourceBindingMap; + resBindMaps[RBM_GEOMETRY] = &gfxPsD->gs.nativeResourceBindingMap; resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap; } else { resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap; @@ -2077,7 +2083,7 @@ static inline QPair mapBinding(int binding, { 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 + return { binding, binding }; // assume 1:1 mapping auto it = map->constFind(binding); if (it != map->cend()) @@ -2092,31 +2098,21 @@ static inline QPair mapBinding(int binding, void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) { - srbD->vsubufs.clear(); - srbD->vsubuforigbindings.clear(); - srbD->vsubufoffsets.clear(); - srbD->vsubufsizes.clear(); + srbD->vsUniformBufferBatches.clear(); + srbD->hsUniformBufferBatches.clear(); + srbD->dsUniformBufferBatches.clear(); + srbD->gsUniformBufferBatches.clear(); + srbD->fsUniformBufferBatches.clear(); + srbD->csUniformBufferBatches.clear(); - srbD->fsubufs.clear(); - srbD->fsubuforigbindings.clear(); - srbD->fsubufoffsets.clear(); - srbD->fsubufsizes.clear(); + srbD->vsSamplerBatches.clear(); + srbD->hsSamplerBatches.clear(); + srbD->dsSamplerBatches.clear(); + srbD->gsSamplerBatches.clear(); + srbD->fsSamplerBatches.clear(); + srbD->csSamplerBatches.clear(); - srbD->csubufs.clear(); - srbD->csubuforigbindings.clear(); - srbD->csubufoffsets.clear(); - srbD->csubufsizes.clear(); - - srbD->vssamplers.clear(); - srbD->vsshaderresources.clear(); - - srbD->fssamplers.clear(); - srbD->fsshaderresources.clear(); - - srbD->cssamplers.clear(); - srbD->csshaderresources.clear(); - - srbD->csUAVs.clear(); + srbD->csUavBatches.clear(); struct Stage { struct Buffer { @@ -2142,6 +2138,30 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, QVarLengthArray textures; QVarLengthArray samplers; QVarLengthArray uavs; + void buildBufferBatches(QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches) const + { + for (const Buffer &buf : buffers) { + batches.ubufs.feed(buf.breg, buf.buffer); + batches.ubuforigbindings.feed(buf.breg, UINT(buf.binding)); + batches.ubufoffsets.feed(buf.breg, buf.offsetInConstants); + batches.ubufsizes.feed(buf.breg, buf.sizeInConstants); + } + batches.finish(); + } + void buildSamplerBatches(QD3D11ShaderResourceBindings::StageSamplerBatches &batches) const + { + for (const Texture &t : textures) + batches.shaderresources.feed(t.treg, t.srv); + for (const Sampler &s : samplers) + batches.samplers.feed(s.sreg, s.sampler); + batches.finish(); + } + void buildUavBatches(QD3D11ShaderResourceBindings::StageUavBatches &batches) const + { + for (const Stage::Uav &u : uavs) + batches.uavs.feed(u.ureg, u.uav); + batches.finish(); + } } res[RBM_SUPPORTED_STAGES]; for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { @@ -2170,6 +2190,21 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, if (nativeBinding.first >= 0) res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } + if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) { + QPair nativeBinding = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_HULL].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) { + QPair nativeBinding = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_DOMAIN].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) { + QPair nativeBinding = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_GEOMETRY].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); + } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); if (nativeBinding.first >= 0) @@ -2189,6 +2224,9 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex; bd.stex.count = data->count; const QPair nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + const QPair nativeBindingHull = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps); + const QPair nativeBindingDomain = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps); + const QPair nativeBindingGeom = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps); const QPair nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); const QPair nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); // if SPIR-V binding b is mapped to tN and sN in HLSL, and it @@ -2201,11 +2239,11 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, bd.stex.d[elem].texGeneration = texD ? texD->generation : 0; bd.stex.d[elem].samplerId = samplerD ? samplerD->m_id : 0; bd.stex.d[elem].samplerGeneration = samplerD ? samplerD->generation : 0; + // Must handle all three cases (combined, separate, separate): + // first = texture binding, second = sampler binding + // first = texture binding + // first = sampler binding if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - // Must handle all three cases (combined, separate, separate): - // first = texture binding, second = sampler binding - // first = texture binding - // first = sampler binding const int samplerBinding = texD && samplerD ? nativeBindingVert.second : (samplerD ? nativeBindingVert.first : -1); if (nativeBindingVert.first >= 0 && texD) @@ -2213,9 +2251,33 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, if (samplerBinding >= 0) res[RBM_VERTEX].samplers.append({ samplerBinding + elem, samplerD->samplerState }); } + if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) { + const int samplerBinding = texD && samplerD ? nativeBindingHull.second + : (samplerD ? nativeBindingHull.first : -1); + if (nativeBindingHull.first >= 0 && texD) + res[RBM_HULL].textures.append({ nativeBindingHull.first + elem, texD->srv }); + if (samplerBinding >= 0) + res[RBM_HULL].samplers.append({ samplerBinding + elem, samplerD->samplerState }); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) { + const int samplerBinding = texD && samplerD ? nativeBindingDomain.second + : (samplerD ? nativeBindingDomain.first : -1); + if (nativeBindingDomain.first >= 0 && texD) + res[RBM_DOMAIN].textures.append({ nativeBindingDomain.first + elem, texD->srv }); + if (samplerBinding >= 0) + res[RBM_DOMAIN].samplers.append({ samplerBinding + elem, samplerD->samplerState }); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) { + const int samplerBinding = texD && samplerD ? nativeBindingGeom.second + : (samplerD ? nativeBindingGeom.first : -1); + if (nativeBindingGeom.first >= 0 && texD) + res[RBM_GEOMETRY].textures.append({ nativeBindingGeom.first + elem, texD->srv }); + if (samplerBinding >= 0) + res[RBM_GEOMETRY].samplers.append({ samplerBinding + elem, samplerD->samplerState }); + } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { const int samplerBinding = texD && samplerD ? nativeBindingFrag.second - : (samplerD ? nativeBindingVert.first : -1); + : (samplerD ? nativeBindingFrag.first : -1); if (nativeBindingFrag.first >= 0 && texD) res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv }); if (samplerBinding >= 0) @@ -2223,7 +2285,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { const int samplerBinding = texD && samplerD ? nativeBindingComp.second - : (samplerD ? nativeBindingVert.first : -1); + : (samplerD ? nativeBindingComp.first : -1); if (nativeBindingComp.first >= 0 && texD) res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv }); if (samplerBinding >= 0) @@ -2295,63 +2357,21 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, }); } - for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) { - srbD->vsubufs.feed(buf.breg, buf.buffer); - srbD->vsubuforigbindings.feed(buf.breg, UINT(buf.binding)); - srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants); - srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants); - } - srbD->vsubufsPresent = srbD->vsubufs.finish(); - srbD->vsubuforigbindings.finish(); - srbD->vsubufoffsets.finish(); - srbD->vsubufsizes.finish(); + res[RBM_VERTEX].buildBufferBatches(srbD->vsUniformBufferBatches); + res[RBM_HULL].buildBufferBatches(srbD->hsUniformBufferBatches); + res[RBM_DOMAIN].buildBufferBatches(srbD->dsUniformBufferBatches); + res[RBM_GEOMETRY].buildBufferBatches(srbD->gsUniformBufferBatches); + res[RBM_FRAGMENT].buildBufferBatches(srbD->fsUniformBufferBatches); + res[RBM_COMPUTE].buildBufferBatches(srbD->csUniformBufferBatches); - for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) { - srbD->fsubufs.feed(buf.breg, buf.buffer); - srbD->fsubuforigbindings.feed(buf.breg, UINT(buf.binding)); - srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants); - srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants); - } - srbD->fsubufsPresent = srbD->fsubufs.finish(); - srbD->fsubuforigbindings.finish(); - srbD->fsubufoffsets.finish(); - srbD->fsubufsizes.finish(); + res[RBM_VERTEX].buildSamplerBatches(srbD->vsSamplerBatches); + res[RBM_HULL].buildSamplerBatches(srbD->hsSamplerBatches); + res[RBM_DOMAIN].buildSamplerBatches(srbD->dsSamplerBatches); + res[RBM_GEOMETRY].buildSamplerBatches(srbD->gsSamplerBatches); + res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches); + res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches); - for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) { - srbD->csubufs.feed(buf.breg, buf.buffer); - srbD->csubuforigbindings.feed(buf.breg, UINT(buf.binding)); - srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants); - srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants); - } - srbD->csubufsPresent = srbD->csubufs.finish(); - srbD->csubuforigbindings.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->vssamplersPresent = 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->fssamplersPresent = 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->cssamplersPresent = srbD->cssamplers.finish(); - srbD->csshaderresources.finish(); - - for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs)) - srbD->csUAVs.feed(u.ureg, u.uav); - srbD->csUAVsPresent = srbD->csUAVs.finish(); + res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches); } void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) @@ -2373,8 +2393,8 @@ void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) static void applyDynamicOffsets(UINT *offsets, int batchIndex, - QRhiBatchedBindings *originalBindings, - QRhiBatchedBindings *staticOffsets, + const QRhiBatchedBindings *originalBindings, + const QRhiBatchedBindings *staticOffsets, const uint *dynOfsPairs, int dynOfsPairCount) { const int count = staticOffsets->batches[batchIndex].resources.count(); @@ -2405,162 +2425,92 @@ static inline uint clampedResourceCount(uint startSlot, int countSlots, uint max return countSlots; } +#define SETUBUFBATCH(stagePrefixL, stagePrefixU) \ + if (srbD->stagePrefixL##UniformBufferBatches.present) { \ + const QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches(srbD->stagePrefixL##UniformBufferBatches); \ + for (int i = 0, ie = batches.ubufs.batches.count(); i != ie; ++i) { \ + const uint count = clampedResourceCount(batches.ubufs.batches[i].startBinding, \ + batches.ubufs.batches[i].resources.count(), \ + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, \ + #stagePrefixU " cbuf"); \ + if (count) { \ + if (!dynOfsPairCount) { \ + context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \ + count, \ + batches.ubufs.batches[i].resources.constData(), \ + batches.ubufoffsets.batches[i].resources.constData(), \ + batches.ubufsizes.batches[i].resources.constData()); \ + } else { \ + applyDynamicOffsets(offsets, i, \ + &batches.ubuforigbindings, &batches.ubufoffsets, \ + dynOfsPairs, dynOfsPairCount); \ + context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \ + count, \ + batches.ubufs.batches[i].resources.constData(), \ + offsets, \ + batches.ubufsizes.batches[i].resources.constData()); \ + } \ + } \ + } \ + } + +#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU) \ + if (srbD->stagePrefixL##SamplerBatches.present) { \ + for (const auto &batch : srbD->stagePrefixL##SamplerBatches.samplers.batches) { \ + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \ + D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, #stagePrefixU " sampler"); \ + if (count) \ + context->stagePrefixU##SetSamplers(batch.startBinding, count, batch.resources.constData()); \ + } \ + for (const auto &batch : srbD->stagePrefixL##SamplerBatches.shaderresources.batches) { \ + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \ + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, #stagePrefixU " SRV"); \ + if (count) { \ + context->stagePrefixU##SetShaderResources(batch.startBinding, count, batch.resources.constData()); \ + contextState.stagePrefixL##HighestActiveSrvBinding = qMax(contextState.stagePrefixL##HighestActiveSrvBinding, \ + int(batch.startBinding + count) - 1); \ + } \ + } \ + } + +#define SETUAVBATCH(stagePrefixL, stagePrefixU) \ + if (srbD->stagePrefixL##UavBatches.present) { \ + for (const auto &batch : srbD->stagePrefixL##UavBatches.uavs.batches) { \ + const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \ + D3D11_1_UAV_SLOT_COUNT, #stagePrefixU " UAV"); \ + if (count) { \ + context->stagePrefixU##SetUnorderedAccessViews(batch.startBinding, \ + count, \ + batch.resources.constData(), \ + nullptr); \ + contextState.stagePrefixL##HighestActiveUavBinding = qMax(contextState.stagePrefixL##HighestActiveUavBinding, \ + int(batch.startBinding + count) - 1); \ + } \ + } \ + } + void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange) { UINT offsets[QD3D11CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT]; - if (srbD->vsubufsPresent) { - for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) { - const uint count = clampedResourceCount(srbD->vsubufs.batches[i].startBinding, - srbD->vsubufs.batches[i].resources.count(), - D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, - "VS cbuf"); - if (count) { - if (!dynOfsPairCount) { - context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, - count, - srbD->vsubufs.batches[i].resources.constData(), - srbD->vsubufoffsets.batches[i].resources.constData(), - srbD->vsubufsizes.batches[i].resources.constData()); - } else { - applyDynamicOffsets(offsets, i, &srbD->vsubuforigbindings, &srbD->vsubufoffsets, - dynOfsPairs, dynOfsPairCount); - context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, - count, - srbD->vsubufs.batches[i].resources.constData(), - offsets, - srbD->vsubufsizes.batches[i].resources.constData()); - } - } - } - } - - if (srbD->fsubufsPresent) { - for (int i = 0, ie = srbD->fsubufs.batches.count(); i != ie; ++i) { - const uint count = clampedResourceCount(srbD->fsubufs.batches[i].startBinding, - srbD->fsubufs.batches[i].resources.count(), - D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, - "PS cbuf"); - if (count) { - if (!dynOfsPairCount) { - context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, - count, - srbD->fsubufs.batches[i].resources.constData(), - srbD->fsubufoffsets.batches[i].resources.constData(), - srbD->fsubufsizes.batches[i].resources.constData()); - } else { - applyDynamicOffsets(offsets, i, &srbD->fsubuforigbindings, &srbD->fsubufoffsets, - dynOfsPairs, dynOfsPairCount); - context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, - count, - srbD->fsubufs.batches[i].resources.constData(), - offsets, - srbD->fsubufsizes.batches[i].resources.constData()); - } - } - } - } - - if (srbD->csubufsPresent) { - for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) { - const uint count = clampedResourceCount(srbD->csubufs.batches[i].startBinding, - srbD->csubufs.batches[i].resources.count(), - D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, - "CS cbuf"); - if (count) { - if (!dynOfsPairCount) { - context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, - count, - srbD->csubufs.batches[i].resources.constData(), - srbD->csubufoffsets.batches[i].resources.constData(), - srbD->csubufsizes.batches[i].resources.constData()); - } else { - applyDynamicOffsets(offsets, i, &srbD->csubuforigbindings, &srbD->csubufoffsets, - dynOfsPairs, dynOfsPairCount); - context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, - count, - srbD->csubufs.batches[i].resources.constData(), - offsets, - srbD->csubufsizes.batches[i].resources.constData()); - } - } - } - } + SETUBUFBATCH(vs, VS) + SETUBUFBATCH(hs, HS) + SETUBUFBATCH(ds, DS) + SETUBUFBATCH(gs, GS) + SETUBUFBATCH(fs, PS) + SETUBUFBATCH(cs, CS) if (!offsetOnlyChange) { - if (srbD->vssamplersPresent) { - for (const auto &batch : srbD->vssamplers.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "VS sampler"); - if (count) - context->VSSetSamplers(batch.startBinding, count, batch.resources.constData()); - } + SETSAMPLERBATCH(vs, VS) + SETSAMPLERBATCH(hs, HS) + SETSAMPLERBATCH(ds, DS) + SETSAMPLERBATCH(gs, GS) + SETSAMPLERBATCH(fs, PS) + SETSAMPLERBATCH(cs, CS) - for (const auto &batch : srbD->vsshaderresources.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "VS SRV"); - if (count) { - context->VSSetShaderResources(batch.startBinding, count, batch.resources.constData()); - contextState.vsHighestActiveSrvBinding = qMax(contextState.vsHighestActiveSrvBinding, - int(batch.startBinding + count) - 1); - } - } - } - - if (srbD->fssamplersPresent) { - for (const auto &batch : srbD->fssamplers.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "PS sampler"); - if (count) - context->PSSetSamplers(batch.startBinding, count, batch.resources.constData()); - } - - for (const auto &batch : srbD->fsshaderresources.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "PS SRV"); - if (count) { - context->PSSetShaderResources(batch.startBinding, count, batch.resources.constData()); - contextState.fsHighestActiveSrvBinding = qMax(contextState.fsHighestActiveSrvBinding, - int(batch.startBinding + count) - 1); - } - } - } - - if (srbD->cssamplersPresent) { - for (const auto &batch : srbD->cssamplers.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "CS sampler"); - if (count) - context->CSSetSamplers(batch.startBinding, count, batch.resources.constData()); - } - - for (const auto &batch : srbD->csshaderresources.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "CS SRV"); - if (count) { - context->CSSetShaderResources(batch.startBinding, count, batch.resources.constData()); - contextState.csHighestActiveSrvBinding = qMax(contextState.csHighestActiveSrvBinding, - int(batch.startBinding + count) - 1); - } - } - } - - if (srbD->csUAVsPresent) { - for (const auto &batch : srbD->csUAVs.batches) { - const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), - D3D11_1_UAV_SLOT_COUNT, "CS UAV"); - if (count) { - context->CSSetUnorderedAccessViews(batch.startBinding, - count, - batch.resources.constData(), - nullptr); - contextState.csHighestActiveUavBinding = qMax(contextState.csHighestActiveUavBinding, - int(batch.startBinding + count) - 1); - } - } - } + SETUAVBATCH(cs, CS) } } @@ -2589,6 +2539,9 @@ void QRhiD3D11::resetShaderResources() } int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding); + nullsrvCount = qMax(nullsrvCount, contextState.hsHighestActiveSrvBinding); + nullsrvCount = qMax(nullsrvCount, contextState.dsHighestActiveSrvBinding); + nullsrvCount = qMax(nullsrvCount, contextState.gsHighestActiveSrvBinding); nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding); nullsrvCount += 1; if (nullsrvCount > 0) { @@ -2600,6 +2553,18 @@ void QRhiD3D11::resetShaderResources() context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData()); contextState.vsHighestActiveSrvBinding = -1; } + if (contextState.hsHighestActiveSrvBinding >= 0) { + context->HSSetShaderResources(0, UINT(contextState.hsHighestActiveSrvBinding + 1), nullsrvs.constData()); + contextState.hsHighestActiveSrvBinding = -1; + } + if (contextState.dsHighestActiveSrvBinding >= 0) { + context->DSSetShaderResources(0, UINT(contextState.dsHighestActiveSrvBinding + 1), nullsrvs.constData()); + contextState.dsHighestActiveSrvBinding = -1; + } + if (contextState.gsHighestActiveSrvBinding >= 0) { + context->GSSetShaderResources(0, UINT(contextState.gsHighestActiveSrvBinding + 1), nullsrvs.constData()); + contextState.gsHighestActiveSrvBinding = -1; + } if (contextState.fsHighestActiveSrvBinding >= 0) { context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData()); contextState.fsHighestActiveSrvBinding = -1; @@ -2621,10 +2586,27 @@ void QRhiD3D11::resetShaderResources() } } +#define SETSHADER(StageL, StageU) \ + if (psD->StageL.shader) { \ + context->StageU##SetShader(psD->StageL.shader, nullptr, 0); \ + currentShaderMask |= StageU##MaskBit; \ + } else if (currentShaderMask & StageU##MaskBit) { \ + context->StageU##SetShader(nullptr, nullptr, 0); \ + currentShaderMask &= ~StageU##MaskBit; \ + } + void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain) { quint32 stencilRef = 0; float blendConstants[] = { 1, 1, 1, 1 }; + enum ActiveShaderMask { + VSMaskBit = 0x01, + HSMaskBit = 0x02, + DSMaskBit = 0x04, + GSMaskBit = 0x08, + PSMaskBit = 0x10 + }; + int currentShaderMask = 0xFF; if (timestampSwapChain) { const int currentFrameSlot = timestampSwapChain->currentFrameSlot; @@ -2713,8 +2695,11 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * case QD3D11CommandBuffer::Command::BindGraphicsPipeline: { QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps; - context->VSSetShader(psD->vs.shader, nullptr, 0); - context->PSSetShader(psD->fs.shader, nullptr, 0); + SETSHADER(vs, VS) + SETSHADER(hs, HS) + SETSHADER(ds, DS) + SETSHADER(gs, GS) + SETSHADER(fs, PS) context->IASetPrimitiveTopology(psD->d3dTopology); context->IASetInputLayout(psD->inputLayout); // may be null, that's ok context->OMSetDepthStencilState(psD->dsState, stencilRef); @@ -3853,6 +3838,16 @@ QD3D11GraphicsPipeline::~QD3D11GraphicsPipeline() destroy(); } +template +inline void releasePipelineShader(T &s) +{ + if (s.shader) { + s.shader->Release(); + s.shader = nullptr; + } + s.nativeResourceBindingMap.clear(); +} + void QD3D11GraphicsPipeline::destroy() { if (!dsState) @@ -3876,17 +3871,11 @@ void QD3D11GraphicsPipeline::destroy() rastState = nullptr; } - if (vs.shader) { - vs.shader->Release(); - vs.shader = nullptr; - } - vs.nativeResourceBindingMap.clear(); - - if (fs.shader) { - fs.shader->Release(); - fs.shader = nullptr; - } - fs.nativeResourceBindingMap.clear(); + releasePipelineShader(vs); + releasePipelineShader(hs); + releasePipelineShader(ds); + releasePipelineShader(gs); + releasePipelineShader(fs); QRHI_RES_RHI(QRhiD3D11); if (rhiD) @@ -4010,7 +3999,7 @@ static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format } } -static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t) +static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount) { switch (t) { case QRhiGraphicsPipeline::Triangles: @@ -4023,6 +4012,9 @@ static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topol return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; case QRhiGraphicsPipeline::Points: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + case QRhiGraphicsPipeline::Patches: + Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32); + return D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1)); default: Q_UNREACHABLE(); return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; @@ -4307,6 +4299,21 @@ bool QD3D11GraphicsPipeline::create() vsByteCode = cacheIt->bytecode; vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; + case QRhiShaderStage::TessellationControl: + hs.shader = static_cast(cacheIt->s); + hs.shader->AddRef(); + hs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; + break; + case QRhiShaderStage::TessellationEvaluation: + ds.shader = static_cast(cacheIt->s); + ds.shader->AddRef(); + ds.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; + break; + case QRhiShaderStage::Geometry: + gs.shader = static_cast(cacheIt->s); + gs.shader->AddRef(); + gs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; + break; case QRhiShaderStage::Fragment: fs.shader = static_cast(cacheIt->s); fs.shader->AddRef(); @@ -4346,6 +4353,36 @@ bool QD3D11GraphicsPipeline::create() rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap)); vs.shader->AddRef(); break; + case QRhiShaderStage::TessellationControl: + hr = rhiD->dev->CreateHullShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &hs.shader); + if (FAILED(hr)) { + qWarning("Failed to create hull shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + hs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey); + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(hs.shader, bytecode, hs.nativeResourceBindingMap)); + hs.shader->AddRef(); + break; + case QRhiShaderStage::TessellationEvaluation: + hr = rhiD->dev->CreateDomainShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &ds.shader); + if (FAILED(hr)) { + qWarning("Failed to create domain shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + ds.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey); + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(ds.shader, bytecode, ds.nativeResourceBindingMap)); + ds.shader->AddRef(); + break; + case QRhiShaderStage::Geometry: + hr = rhiD->dev->CreateGeometryShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &gs.shader); + if (FAILED(hr)) { + qWarning("Failed to create geometry shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + gs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey); + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(gs.shader, bytecode, gs.nativeResourceBindingMap)); + gs.shader->AddRef(); + break; case QRhiShaderStage::Fragment: hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader); if (FAILED(hr)) { @@ -4362,7 +4399,7 @@ bool QD3D11GraphicsPipeline::create() } } - d3dTopology = toD3DTopology(m_topology); + d3dTopology = toD3DTopology(m_topology, m_patchControlPointCount); if (!vsByteCode.isEmpty()) { QByteArrayList matrixSliceSemantics; diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 50ea3fbbfe..96c7818ee9 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -221,39 +221,66 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings }; QVarLengthArray boundResourceData; - bool vsubufsPresent = false; - bool fsubufsPresent = false; - bool csubufsPresent = false; - bool vssamplersPresent = false; - bool fssamplersPresent = false; - bool cssamplersPresent = false; - bool csUAVsPresent = false; + struct StageUniformBufferBatches { + bool present = false; + QRhiBatchedBindings ubufs; + QRhiBatchedBindings ubuforigbindings; + QRhiBatchedBindings ubufoffsets; + QRhiBatchedBindings ubufsizes; + void finish() { + present = ubufs.finish(); + ubuforigbindings.finish(); + ubufoffsets.finish(); + ubufsizes.finish(); + } + void clear() { + ubufs.clear(); + ubuforigbindings.clear(); + ubufoffsets.clear(); + ubufsizes.clear(); + } + }; - QRhiBatchedBindings vsubufs; - QRhiBatchedBindings vsubuforigbindings; - QRhiBatchedBindings vsubufoffsets; - QRhiBatchedBindings vsubufsizes; + struct StageSamplerBatches { + bool present = false; + QRhiBatchedBindings samplers; + QRhiBatchedBindings shaderresources; + void finish() { + present = samplers.finish(); + shaderresources.finish(); + } + void clear() { + samplers.clear(); + shaderresources.clear(); + } + }; - QRhiBatchedBindings fsubufs; - QRhiBatchedBindings fsubuforigbindings; - QRhiBatchedBindings fsubufoffsets; - QRhiBatchedBindings fsubufsizes; + struct StageUavBatches { + bool present = false; + QRhiBatchedBindings uavs; + void finish() { + present = uavs.finish(); + } + void clear() { + uavs.clear(); + } + }; - QRhiBatchedBindings csubufs; - QRhiBatchedBindings csubuforigbindings; - QRhiBatchedBindings csubufoffsets; - QRhiBatchedBindings csubufsizes; + StageUniformBufferBatches vsUniformBufferBatches; + StageUniformBufferBatches hsUniformBufferBatches; + StageUniformBufferBatches dsUniformBufferBatches; + StageUniformBufferBatches gsUniformBufferBatches; + StageUniformBufferBatches fsUniformBufferBatches; + StageUniformBufferBatches csUniformBufferBatches; - QRhiBatchedBindings vssamplers; - QRhiBatchedBindings vsshaderresources; + StageSamplerBatches vsSamplerBatches; + StageSamplerBatches hsSamplerBatches; + StageSamplerBatches dsSamplerBatches; + StageSamplerBatches gsSamplerBatches; + StageSamplerBatches fsSamplerBatches; + StageSamplerBatches csSamplerBatches; - QRhiBatchedBindings fssamplers; - QRhiBatchedBindings fsshaderresources; - - QRhiBatchedBindings cssamplers; - QRhiBatchedBindings csshaderresources; - - QRhiBatchedBindings csUAVs; + StageUavBatches csUavBatches; friend class QRhiD3D11; }; @@ -273,6 +300,18 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline ID3D11VertexShader *shader = nullptr; QShader::NativeResourceBindingMap nativeResourceBindingMap; } vs; + struct { + ID3D11HullShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } hs; + struct { + ID3D11DomainShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } ds; + struct { + ID3D11GeometryShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } gs; struct { ID3D11PixelShader *shader = nullptr; QShader::NativeResourceBindingMap nativeResourceBindingMap; @@ -707,6 +746,9 @@ public: int vsHighestActiveVertexBufferBinding = -1; bool vsHasIndexBufferBound = false; int vsHighestActiveSrvBinding = -1; + int hsHighestActiveSrvBinding = -1; + int dsHighestActiveSrvBinding = -1; + int gsHighestActiveSrvBinding = -1; int fsHighestActiveSrvBinding = -1; int csHighestActiveSrvBinding = -1; int csHighestActiveUavBinding = -1; diff --git a/tests/manual/rhi/geometryshader/buildshaders.bat b/tests/manual/rhi/geometryshader/buildshaders.bat index e15ca63aea..6da26a6a2a 100755 --- a/tests/manual/rhi/geometryshader/buildshaders.bat +++ b/tests/manual/rhi/geometryshader/buildshaders.bat @@ -1,3 +1,4 @@ -qsb --glsl 320es,410 test.vert -o test.vert.qsb +qsb --glsl 320es,410 --hlsl 50 test.vert -o test.vert.qsb qsb --glsl 320es,410 test.geom -o test.geom.qsb -qsb --glsl 320es,410 test.frag -o test.frag.qsb +qsb -r hlsl,50,test_geom.hlsl test.geom.qsb +qsb --glsl 320es,410 --hlsl 50 test.frag -o test.frag.qsb diff --git a/tests/manual/rhi/geometryshader/test.frag.qsb b/tests/manual/rhi/geometryshader/test.frag.qsb index ab1aa3d02e3ffc4e8925ee5790664fcd6197d3bc..b6a5877b951c0f274ba3d1c1990fc83677cd8c02 100644 GIT binary patch literal 456 zcmV;(0XO~t00cC6oV`*_Yui8&9e>sKwzO#i$*pYh#im6ljvGQml7bJVU}&j}uR=(& zB2ctuwK6TikpGZde`znJnOUt|RcWtZR=)Zne=pi7Mz^x%m>pF>kid5q%dd^elVtV{*gFy(u7=}p56_mV=a{%} zuvZupm+9(vSFe%P)%pvp>Zj1r{mNxf{&z$=cwS=EH+esBx-&f?w9Q-?G~SxA$?ga1 zP-d}6`N`PkVa8T6^kWTN$I8)OPQ z`NdX#?~o~(`-;y$zW=mvr&45@`yp4WT$TN5Dg2zz7w%_IMxnB?Zz+-p?q8Ln$fflK yO)K4PwmYM#h!5YxFm( zmld2_TZ!$hQ^eUK(KC5=>dAN^=2;vj2AC$3>0FLet@7X(oXh})P@ zr^T-q)TRxK?oiG2vyNHvdN;Zs^%r^6_s>1P-!z?!+Hb`XX5=ncC4I)AArwsm68(Qww*WQfjzqxJI0y0!eoEFIRUF>-d|#?enCxB rulhqc{sTx8>orcUjr&A*m!+!J>{#me75Ss3)c(NxC++APMQm&$Qzx;8 diff --git a/tests/manual/rhi/geometryshader/test.geom.qsb b/tests/manual/rhi/geometryshader/test.geom.qsb index 72ef3bc075b0e21c3928b2e8a73680e8c02d0d51..9aa4a0cf98eb4f084f8f717d3fc59776f8cbe130 100644 GIT binary patch literal 1222 zcmV;%1UdTv01c3Mob6R@Puo@$z6rE|!O)J;KqGrAa%-ejGatR_$|Vey#jr9YdXQuf;rxte;U57Mz>uqA3 z1P^oEf`1Y@yuKeW{IV9=(;;Qg<{7-6*jl?ob_ThF=<#E4M?FM#D##lQ&KT9tU>*_2 z40@WyowBb6`#!J??mn5ryboxdOPuQy)O-LAwzb6F>DXsr=X(77hO?T4?-6ETfQ#)s zF!mR)=Xk!8D)#Bb9G;@yBK4mZ@t2Eh{z1q!aPusNF_RkRGX;B=>;oc-cP=Kd&q3V*>m?Q$^Opd%##HZzzUs*7O*1M-#cXk?TMQcYyssTx@>;jP>(9 zun&PxC$Nuz-^H1xfUQ#%p36LDHG+2qI?KYhPCPuXhtS0ccpf5#{XCN*<`i*o?FHbG zUBdm2QEj%%nA13XQQYE%xC-J__;#r#&;2nt*#9H2CEyE*-fM~8qw_5T-=S$&13bi* zF;lMh9XMCvUrKO3xrB2K_zt0&AU4D}pEbz3V?7Sw4xb?ASE|MuQlSGip@UDMgKsID z?PtKAiddu1M88H^Pp^sdFM6xt|E59w{*#ef6TN>}sW-DHrt4XbEfGF|WH1fKfm&I^dFbbtY`EjvQD&z~ra%G`dDi*4ha;-=8@~FP+ zc$UwXvBH*R@8=JU1RTenn9ZWBFBZeV$ZwpU$*k1asWlx>3)<3i(xan=d+vk|ZG;!1 zUsaqKN*d7{r#Y@-oaOq;eA91!o#5Fxw)__~B=b}QdLDdk*sWdHBBym?vgce;E~w%s z(R)(A_f$c*^}i(EMM_qJ@$-Nix6{$32RZ$}) z>{_Sh(U$%8{GGk6FSd3*>*Y5|A8peOWU?e(^QGnarmG$1^?o8~i()#B=2uR;?U}yT z%Ob||ujY2B=7g9R%e6Q)EN66L8HEQS4R_+{ToD~ecO|;a k`LObpDo*euZ^2mabWFRYh1^lpIZZ-Msx5f_2FchgtNx~Pi~s-t literal 991 zcmV<510ehW01F~`ob6TJP7_fOJ}u>M`PB+2YCQyqs`^L;bl%sDfqLWmwAM3?A1 z5y99~(GuIauvG4G5){sj6FXiTA|Y1}DuW!N*o z61e+t4C`K_H5oeBb>zGT4Yu{r-5J;?V5i&q{QA9$gPTJSOlYy40mgh5d-mr$DPbQC z_2CZk%~SnR(fL+#&hLbDLz{cihn|$tpE1}=q=YR)x9``#)x!EqDPs88> zzxfk>MfeSY+oYV__nXjQ{ynf;z;mJ6%c0tX^DO}1pl+8u+{YHsQ_lAWnoHnsg*2B> z(Odz(L1@DB^)Zg;8RWU+dF;X+F2mDzNqV+-?5Zo9)tYKKW$lPu zS`D>rH+R`bR`Ml6_H9*@T%T?PQFc@6RDe{JC{w0oK^AFAr3{bvy*m2t^SWClS6%mP zT^Vvt&YKxS-jJ5RqZ!*-mBCc9hGPvB;KcJkC5Z zLvY7;zrJP3%Dm+}2E2K2C{t2rQs1&2-7CvTONWl;@3|5>wCP`n@u%dZkk?7xJVotYy|J24d>MEi++YflB;*8h?C N7e~T-egkGGb;|N#^bG(2 diff --git a/tests/manual/rhi/geometryshader/test.vert.qsb b/tests/manual/rhi/geometryshader/test.vert.qsb index e317e297cf37571675c50d6a13aa0670b4f851c7..7238d8037b66db246743ca0ddd23b39a4faea13f 100644 GIT binary patch literal 591 zcmV-V0PPz1%HSC%m3mR(Q|T7mX{4b_`w4=H}^T`JkOJJ0{}J9Vc=Sa83Yi42MSjJ zK4KM0{^o#xk1Fqz3^FGbb9o%@;u!I~s(mllt#*7?hGDhq@e5P0r*@^EFb8H|=_+zZ8a7`26Xpj=u zCf1Xy8vDA7&lS#5?C^P&^&jF{aQ$kcqy3~DBI&KdP4-5)E}z#JBaJ$17_3oG=A(l= ztutSR`5KU3y5?)}+|quky_0l*dr9^8xtDxBMUQ6gQVIWw$P(^{thK>>?-8vf9yJCz ztjU;>!!{Ws{sF3y-aYPba-Mv>#(MI!#dDx|J4aidOtH_{D>54j^+6@7^zO4uPgGY zf{#dr@mR^>;P~{+ISPX)a*q93tk_hkK|Yrs-hMpl_fOy0Xy^L=eymCa1vAJoJj+>I zq|?ATD(5dF(Nx8uoa?DvmDjVq@>voGap5{1y{9U(Od^-HvLR7X&YT9Wk<{Hma?nM2 d#43JG;d-bxbX6SsC6Yzy*DGJTjz6?I4SoabD6#+m literal 429 zcmV;e0aE?|00awooV`*_Pr^VDowj_gf*=Zt#;oB2(U2l&Oo(46JaEwX0}KITnjl4s zB*vKdJN%_yjLvLdg?RMfB-8D_dGqG&wnUVmFf7g-O~|K!JeqR)G-k|^;unJc9uC&Q z9I^+FT}jGlMJd_>nkUFlcDgs+dN3W-TZgXHvyhV73MI{ZjPt(diC@Zau5w;d zoHfFT)(EqJSqqpAOw>F4jIa)?i{1`23XBTA%Nz%sBEQK+YR(e##Z>~n*7=!2O=1uG zH0E#fUV)!Bb3#9nhBCb|T81~NwXx3tlNnjeurMQQ?k5cKl!KlFy*x!9J=DwN-lBft zu9@z)GvRNdS9~3@M;qshKJEu2ab8a_s{p-gMia(kh|vO81ZFK@C19d|#nWWo2KtMr zi?0jji>ET~LC$*0PRihavg)x>rWpPW-dOK6k8x!-d<;B)tXmCNsZsCQf0|ZDe!n*r z@I<>c?Tz(p*l+5IA9#Ycm74k9K#OFxre2ihxEtMGq0U{*Z&f4yzHZdrT3fv;^~=dQ X4leQVS6G&W=wnob#ZHTUL@A; diff --git a/tests/manual/rhi/geometryshader/test_geom.hlsl b/tests/manual/rhi/geometryshader/test_geom.hlsl new file mode 100644 index 0000000000..e58659252b --- /dev/null +++ b/tests/manual/rhi/geometryshader/test_geom.hlsl @@ -0,0 +1,26 @@ +struct VertexOutput +{ + float4 position : SV_Position; +}; + +struct PixelInput +{ + float4 position : SV_POSITION; +}; + +cbuffer buf : register(b0) +{ + float radius : packoffset(c0); +}; + +[maxvertexcount(7)] +void main(point VertexOutput input[1], inout LineStream OutputStream) +{ + PixelInput output; + for (int i = 0; i < 7; ++i) { + float theta = float(i) / 6.0f * 2.0 * 3.14159265; + output.position = input[0].position; + output.position.xy += radius * float2(cos(theta), sin(theta)); + OutputStream.Append(output); + } +} diff --git a/tests/manual/rhi/tessellation/buildshaders.bat b/tests/manual/rhi/tessellation/buildshaders.bat index c44916067d..c9afe1b178 100644 --- a/tests/manual/rhi/tessellation/buildshaders.bat +++ b/tests/manual/rhi/tessellation/buildshaders.bat @@ -1,4 +1,6 @@ -qsb --glsl 320es,410 test.vert -o test.vert.qsb +qsb --glsl 320es,410 --hlsl 50 test.vert -o test.vert.qsb qsb --glsl 320es,410 test.tesc -o test.tesc.qsb +qsb -r hlsl,50,test_hull.hlsl test.tesc.qsb qsb --glsl 320es,410 test.tese -o test.tese.qsb -qsb --glsl 320es,410 test.frag -o test.frag.qsb +qsb -r hlsl,50,test_domain.hlsl test.tese.qsb +qsb --glsl 320es,410 --hlsl 50 test.frag -o test.frag.qsb diff --git a/tests/manual/rhi/tessellation/test.frag.qsb b/tests/manual/rhi/tessellation/test.frag.qsb index d68037322105db2f4cefd246f7ae9cec777e5b0b..4ec03e570007751b0da257bfc0054ae366b9913d 100644 GIT binary patch literal 581 zcmV-L0=oSG00r`RoXt~Ri_=gLoqlY)yIRWx zE4mv>vnLUend|iBEVjK-6h!f0Gtm!;cPul@DOe(l{HY|T-JbX;B(8-9rjTft$&cir zVfF^%T8NeIzTAAN@OjZ)|IqyZ?9#hD(*9WA6NUAhV&+SR^b6fVqTxGMPuJt2v0G@04^jwxGyBg}3#$q<53-(n28wwW5QGO^$I$|s}a`Qrn7rQEr T!xe$+mG5!&B^T>A(jhgBHUTEh literal 425 zcmV;a0apG100aGaoXu0sO2a@9o;Lm6R_zbyO;&noQA%p72%#$U;H3w}2Ph#;+d%A= zGzLTj-@%(t;WPMDUPNb-X<1RkqXU!O`SzQ?-3b8X03d^!LfwQ2M&N(~A2mS4K!pz$ z_$uU4g9-9%n8HBw%KYN>S22>irZU5Z8EI$jLSyyn z>l^IN5fr|Cr*6ZhuN*t1v%WN25)m1>PESq(dpc0Q3ap=r-kf+{8I7ETB_idG<&Evl zn=NrKB+5Dlx=_$2lMiI4ZMH1&AOzhG`EYm7TE|c8?s^^b|CLKJ)?WX`NH_A-g@6Lo z8LdJ(eytMD6|EP;>tTBtj@!K>6XFRo*0Zw(`FK)DS2>EPWz-7t2+vat+!4OZImj++ zb{%u3aos~7icb4&+|gu9)E(qgoYkaD{1$k^2)EcSGDdvCe1rKVu30d@#B~z3k9IEZ zjpXs{7_xB<8Eul^5Xs`&=hz$Ue}!l+zKa9{4XZGg(y%IH6#o*dr}}H`U*U7A;}o+N T`RpAdoFxB{{+93wTUeW*9l_GO diff --git a/tests/manual/rhi/tessellation/test.tesc.qsb b/tests/manual/rhi/tessellation/test.tesc.qsb index fc9dfbaea1583fa73f4106fdca43f574fff4ba52..57451d7c08e5d803ce5d78ac5974f8e627ed283c 100644 GIT binary patch literal 1202 zcmV;j1Wo$@01i8Nob6P9Pa8)NU9d^$5d#U7B!s|X($pr@G1#O8V*)V^wS;OEP*ur7 z(dm4+CpmZ4-Pu)?BK33hBlOEu>X+#cscL6--8dte=+##W}N>}@4;hTVODdt-Oeuw7QVoW?i{S#OtYy{Xy3>yWOfNq4be|3n? z>JXjPAvzJp_3@b(p~3b}%$^|@^Oh+lftXK;!%s+x=usraZR{B@!5#44NGCl-4J} zxQ5T+dx{#^&H!6P?}uqV!(FrH8m+56EGfP~jcd?kI~VJ99{Xk31>{@Cxi^t7s`&-2 zo3Wa|gzp9P+1`rrx51Ce)xYRZh4DWK8Kbp~o_`|r zTm6O5=sRVM-|O!bF^Sl}h|j*15DH@*-tSY~oI1OHe;l_qruy>=Ju8F5z1aiK9PZg`yn~m>@fw`Jsk>XM!y<|QZZbyp&~{#aTj|<< z;CQYqY~-aK7%lUI*9kL(hK^+ivMdW(Nl3|vTrJNsLyjoRymHB|Z54P^@mii=FPxQz zQyo_`9aj^HXLLQMA-T3p*7#^h8qT@QG+XbgZWqDT16k&H<<%S>#5uKt;K=UUty(9v z{d)e4@)UFV(lwm*8*nzRJdShCl=f~CQwgRVNYf4q^`-nPMJc(?Z zq4m8&-gI0mqps_iu^qKtlZ9RBwAWd^HKB2(370)UT3tOZN*lTM<=3fn>d1Q5^YrueYrR5NaDNMW Q*{Bb(?^2C_0oquX1XwtACIA2c literal 840 zcmV-O1GoGD01Bgcob6QWN*hrSo|uiMt2JIy@0yLVHiRs!=p*!H3VoSgptLh*zY~{j5Pz2*IG!`#eDlqmory%$OGFXuL2}5YL-MH3 zyTM45H~q$EeLb*~T^|WZGfCLSw)8PH?+;Ihu^G@wm8 zyY@F>h_(ni)9{EHs1OL4G-hRJzOePTX5SkLR$maquso@cPi>N{DEU-EBzMJL} zzO`sB^O^5p20ccN%g_|N5a@Lg_cZJh@}=?a3i9ci*ZHgjYJLLWI`qZf2=KSS*Y#A9 zZwq{}w*&R;;9h~f53P#I5mWs$Fjs(KQK2Hus! zyR^Lmd!H@o;VSyN0?is`b`3t^NpH)Tsazm;89c4M8Ol}b_s>5X9e>WSEJ+xhpubH;pXgZ#2mDY-u-8Adx@4c&5meH1TVK=Rs zRmxe6R88%wdl%;|iKtmc<+9rLMM*A)UfpY)md>i(sgCP29oHu^&un|nr6sjxbLI!r z;^n-tvTy6JkKHzckDppKiC12qBa1n&>}K=CZrk-b(T{JKr-*WexoW!>+1%ZJMEOf1=KceCc$% SyjuL<>VK)#YW)H8)qEDiptmIe diff --git a/tests/manual/rhi/tessellation/test.tese.qsb b/tests/manual/rhi/tessellation/test.tese.qsb index fe99cd5001aaf9d6ea79aefb63063befedfb3d1f..4ca3c35e9237e48f1162bf1233d8e9e109776dda 100644 GIT binary patch literal 1522 zcmV$wjeYVffPz4HkDQcORXW9 z)X`+7Yi3efSbgxpSJ(2@ALsAz#ie_n`A+8K0*eP9nYB(j``dee`+8>~ZpFqrWB#(o06fq_+n=u@YaT4`RAjU~mZ-lY_G~UNi=UMnBp+ATCXW`HCc_SyT z`vP)e`-?(<3!Z1BcAml=6nV?+gwy}qd8oF4d?nH@H-@Nk3K@*P8eKV^T*KrPFyU10_;PB|5NZE zHTW~YHUBjDtv>!4=rn&882kSU>@&p88Zkdd%$yN34_wEbMa)89%sJ?E%z0pWBj#1a zW!)dZuA#SAkq7U_brIb|=D$S~x(++m^R6slK9-SZ5jf|0Q{gd(*~44VaZW6M317yK z5yIGQ>`EGX9rq6677V_-z<&c@3I2DDT$YSn%ze2BozCSxu#(}s+~>>vSca{h+gD<6 z7asy=8~$cgMRW)B%=o^n0_T~r{0*>&2KOT|xQA=NHTOEWEra`8;F|j}ur<`n*msEe z*ogN;4DR4l;5y#-h*vP;Z2;Hto&kGm#M?y7XXs-Y*grJw>uTa+6#o~HFrwFho<#M^ zuI&eo=gPU+ytIQl}jmB26Q>#1fwj~|6 zm`Vkq->HZ4d8e6rm6G(dYvH_X@9q?p)NFaRP=-$1HsxA-r{#p527w2}(Q%!o=eLpD=lG@MwLHH#+|F?$Gsjg{8=FM9>p2a{eaKkIbGx;* z>IDwmC~S_BmeVqm$&ku%H}ab~(`K4I*6koDd7j_M?OAe0!m{v2%YDl*oqeO}OUo+u zCzsokGmA14Q0kl{x02{ggMEv5Sl4YUSahGLzD!1UBfmMk6s<1|=uv<+m>n>9N%0O+ zslHYFQ*@t1rMqhLh5Wlcd$(u*)1L8vJ+twiCI7;jl--?9m`=S)8_Qrfw(VeJZc{GE zwa1F}KJ6P#*EDk6z-ic#Nm;%37#`3`>s?%}h4r6?M4FR3y6+2ewYpYbFIQKJJqC5v zt_4}DR;rH%c%41FHI!Got>1f6s#YH@|!!bar2;)rcxyQVbPbQu?ZRZV<|9CnOg&tef%3vU2Vg zB|~Cdy%Et-cnerXx1K&fPi8#0L9agTiowmtBL|*Z^&evWeXm zWxLbLL?g=dCY6-&(U{=RfA6|Q;eO=)L+McSF Ywj0j3!;bI9lQ>A5H(x#f0rev{u<*G9^#A|> literal 1174 zcmV;H1Zn#K01ljZob6XzbJJE3KDI+Hf?T15KrshWS}9IlI~SVNgeEw}NipFPN=rlP z3STmsu_ccsyMzu8edudv`r2RGmrlDYeaAjyy9^IJqM74pzuo=5-95*$B7_(fLd0ps zXiW)6xFRn+QK!`+Btc93i%aw_j+Xd4L$PfUyi=aa9ThJrrxxCoL{@Cl-JTYc2t5ta z5ly-~3v^qHm{B+5B<)aW71SIwB8FUZ!ltk$)#y-4TU5F!yZ@K+E>|KViEV?7uK2^n zPPOGbo-0>ZGP3F$b^Fw72WHT6Z1<#I^_OM2{L8Yewd`_0VRpUbRVpRFX_p=M#FCDi zGYmgywabBg*{&JC8j`Mt9jwVlr{QFEe3SR;UMn{|&T*qK#|@*7j)}12ITb3+aZL+#p43Z^ zJl{bY$)>4jxg<@~B$wkJWscK&%o1ljt@?i6^IDbkD@&#%BC~IeJhimYmA8hzwya!# zap_kwwIxlTO6MYZltiZooLa=gzV2ATqUJ>XnWmaX=6HB3%AXzZqX8ALG7#{Z^xhZ- zpHCh!j@niigFtA5_w7>lyY>MLz_gZ<;dWc+e`1Nm>iEZqVANbs+e`o(N+uYWE54{*2(C ziZk6G1@%{9F<>zbivwex0(~lMj~Hi>uXvTcsPQUnOhi9C3X36bTf^eOcA=%P0%@H` zuR^o0YxV-_oCIHTNRP=OJtl|rs4(W`*(Noe1I<29QSq>jM3@^7XP*dP3?!|2is!yZ zv3DQQ=Qwo{z~k5I+&>M0=n(j4*dZoI|bb%fX%m#u`(i_ll8%Jq^uEWY2(e z1RAs0n^7#*m_t9a(3lJRjWG6K!2JyRoJVc~{!7rGM?TvNT20*dWz@v+SA=@KiE2vr z^{sNQp*NnD#9mwj$92(ry~@G9(Zxo>vlRocnv2y}QyP6Ke^%@HOY}DedlNo2v)e+w zens{kY&8S6_knT!Mfg*-VS|U2=_kPBi`#R?DIw7 z9CIbqjrQR(Vz}0;z<0>v8GVAeO>11-^G*2vATG8)1$I^A{|x*S8ovo#@h^ej>f=wr zr}&qFasF?>K8NnIruhXl)0$=mxYAsKX0}gr6+Wf81}vj#u0xl7e*(LO*{-7wJ{ub% z`W`a>9onG{#Ic{x%2(JQORF;noa?+D;yn(1hIioOn%Mptxs0D9gt2X$l}Y%O?hbUb z8sA;uzk@H2{JUB$yIL*!dHDuDRm(kKc`dilm&@}gAXe?$w_@-t-UrSx{LFYLqVIs( zGyc9j0?vEJ_G4i8HSQ;3@EjfjSKLp*ZE4)!0ax75fE}V=#=eK@qoZVAfYZE~fKATN1S#3+eqEMz&jJZ5TFFg09Rn1Hzuah3MJTAKHM1f_oJsl7EyYQQ=?U^I^{ zQW-a}W!hUO-IJ;x^s9|0H3-YoXQkeP%uM`a&!#!R2CmzK$m4*?nPG?Q_HyEQFSo(DGdIV2d7iI| zC+?jv`pZk=-{;shj^ANl#qaRl=rO$#>pjJuQV=~B;`~Bn1@}X)ZIkn#BDxy(Br%9# z1;(@(w#69fcd$CD?;gh&_?-H9jeP21o99Ned4ZK|GhfxQ%XQP4dI!HTIH-!idse3Lopdx2V&&#5sSF|5Bn)>PoScN4n9Jd!V;z^oD{3zaM5});zgjFMc;Ek<7bUVjq z=jM^;`o4KQ9E}6+YEE1{7w_MGIBK`g-qf0Lf@~@}tz%=$)!XA>L0%1Ixq6~)f~)KP)P0 wNCHbLlA&(sNKzcBCMS@1JPX`t2D2AK9B&Yez2RJ<>D-@l{@F_V3pPQd^%5&&>i_@% literal 527 zcmV+q0`UC+00ozLoZVDSZ__{!9oy+g78()?DYQwusFy^b$e{rtMdjlZ4m}j{1EMI2 zkR=mWaj=9C62F5Vg~W}Y!Ue$_`)zBWl{hofcs+05yqQ^VA|mTjm=CYZnIw`*BrA9# z3t)k6{-nw8W@HLh3}2GzUBUF=HOXZBSH@M^|7t;@?mcG}wXcWSe3?ec!X7;g?L0Lm zp1e=qtvYcsovai;wqe&s3!BZSNA@g9BSnXo(|{DbY&=ckWO*5_f1yT>$&zSh-%g@M zr)xeK3wslfPgx2nAP+jO^aI=Ph23FJV;N8=_0bp%RZ%St`?+)gU(Sae^uzyZQnlH| zp#HbOKitp*FtRBJL>sud`rWVLChIynd41ALSF_&WQ7HMX3(jxg4XNhu6}YRh1-}Vz z!Q1ecvIecf-0Coom{-DlVp?T{r^805qPqLk(75$S+-9tL+sM+qd(a4|(ZrknJ}rC) zd<>t*+W&1lH@T;FpK+CXEyRZWYF?-4*J+qMw<6csyY3AcZxPcPHP-N0qn4jzVcJuj zdI9ws patch) +{ + PixelInput output; + + float3 vertexPosition = uvwCoord.x * patch[0].position + uvwCoord.y * patch[1].position + uvwCoord.z * patch[2].position; + output.position = mul(float4(vertexPosition, 1.0f), mvp); + output.position.x += sin(time + output.position.y) * amplitude; + + output.color = uvwCoord.x * patch[0].color + uvwCoord.y * patch[1].color + uvwCoord.z * patch[2].color; + + return output; +} diff --git a/tests/manual/rhi/tessellation/test_hull.hlsl b/tests/manual/rhi/tessellation/test_hull.hlsl new file mode 100644 index 0000000000..3d09307159 --- /dev/null +++ b/tests/manual/rhi/tessellation/test_hull.hlsl @@ -0,0 +1,40 @@ +struct Input +{ + float3 color : TEXCOORD0; + float4 position : SV_Position; +}; + +struct Output +{ + float3 position : POSITION; + float3 color : COLOR; +}; + +struct ConstantData +{ + float edges[3] : SV_TessFactor; + float inside : SV_InsideTessFactor; +}; + +ConstantData patchConstFunc(InputPatch ip, uint PatchID : SV_PrimitiveID ) +{ + ConstantData d; + d.edges[0] = 4.0; + d.edges[1] = 4.0; + d.edges[2] = 4.0; + d.inside = 4.0; + return d; +} + +[domain("tri")] +[partitioning("integer")] +[outputtopology("triangle_cw")] +[outputcontrolpoints(3)] +[patchconstantfunc("patchConstFunc")] +Output main(InputPatch patch, uint pointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID) +{ + Output output; + output.position = patch[pointId].position; + output.color = patch[pointId].color; + return output; +}