diff options
author | Liang Qi <liang.qi@qt.io> | 2020-01-04 15:32:34 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2020-01-04 15:32:34 +0100 |
commit | a503bf54705d89204007e8f887b668fe5ef519fc (patch) | |
tree | b2d1a452da39450eac78a1aeb1df116a73f64b23 /src/gui/rhi | |
parent | e65c43fd0ffa57248e7d750570b7deae171a82f5 (diff) | |
parent | 1f87fb359fdff14e42662384a9c8a0bcb3837671 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts:
src/corelib/tools/qvector.h
Make QVector(DataPointer dd) public to be able to properly merge
5b4b437b30b320e2cd7c9a566999a39772e5d431 from 5.15 into dev.
src/widgets/kernel/qapplication.cpp
tests/auto/tools/moc/allmocs_baseline_in.json
Done-With: Christian Ehrlicher <ch.ehrlicher@gmx.de>
Change-Id: I929ba7c036d570382d0454c2c75f6f0d96ddbc01
Diffstat (limited to 'src/gui/rhi')
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 79 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 1 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 104 | ||||
-rw-r--r-- | src/gui/rhi/qshader.cpp | 7 |
4 files changed, 151 insertions, 40 deletions
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 3fb2ec38a7..ffaccbad71 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2378,12 +2378,23 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps) f->glUseProgram(psD->program); } +static inline void qrhi_std140_to_packed(float *dst, int vecSize, int elemCount, const void *src) +{ + const float *p = reinterpret_cast<const float *>(src); + for (int i = 0; i < elemCount; ++i) { + for (int j = 0; j < vecSize; ++j) + dst[vecSize * i + j] = *p++; + p += 4 - vecSize; + } +} + void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs, QRhiShaderResourceBindings *srb, const uint *dynOfsPairs, int dynOfsCount) { QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb); int texUnit = 0; + QVarLengthArray<float, 256> packedFloatArray; for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) { const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data(); @@ -2411,18 +2422,64 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC // so this should not cause unaligned reads const void *src = bufView.constData() + uniform.offset; + if (uniform.arrayDim > 0 + && uniform.type != QShaderDescription::Float + && uniform.type != QShaderDescription::Vec2 + && uniform.type != QShaderDescription::Vec3 + && uniform.type != QShaderDescription::Vec4) + { + qWarning("Uniform with buffer binding %d, buffer offset %d, type %d is an array, " + "but arrays are only supported for float, vec2, vec3, and vec4. " + "Only the first element will be set.", + uniform.binding, uniform.offset, uniform.type); + } + + // Our input is an std140 layout uniform block. See + // "Standard Uniform Block Layout" in section 7.6.2.2 of + // the OpenGL spec. This has some peculiar alignment + // requirements, which is not what glUniform* wants. Hence + // the unpacking/repacking for arrays and certain types. + switch (uniform.type) { case QShaderDescription::Float: - f->glUniform1f(uniform.glslLocation, *reinterpret_cast<const float *>(src)); + { + const int elemCount = uniform.arrayDim; + if (elemCount < 1) { + f->glUniform1f(uniform.glslLocation, *reinterpret_cast<const float *>(src)); + } else { + // input is 16 bytes per element as per std140, have to convert to packed + packedFloatArray.resize(elemCount); + qrhi_std140_to_packed(packedFloatArray.data(), 1, elemCount, src); + f->glUniform1fv(uniform.glslLocation, elemCount, packedFloatArray.constData()); + } + } break; case QShaderDescription::Vec2: - f->glUniform2fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src)); + { + const int elemCount = uniform.arrayDim; + if (elemCount < 1) { + f->glUniform2fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src)); + } else { + packedFloatArray.resize(elemCount * 2); + qrhi_std140_to_packed(packedFloatArray.data(), 2, elemCount, src); + f->glUniform2fv(uniform.glslLocation, elemCount, packedFloatArray.constData()); + } + } break; case QShaderDescription::Vec3: - f->glUniform3fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src)); + { + const int elemCount = uniform.arrayDim; + if (elemCount < 1) { + f->glUniform3fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src)); + } else { + packedFloatArray.resize(elemCount * 3); + qrhi_std140_to_packed(packedFloatArray.data(), 3, elemCount, src); + f->glUniform3fv(uniform.glslLocation, elemCount, packedFloatArray.constData()); + } + } break; case QShaderDescription::Vec4: - f->glUniform4fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src)); + f->glUniform4fv(uniform.glslLocation, qMax(1, uniform.arrayDim), reinterpret_cast<const float *>(src)); break; case QShaderDescription::Mat2: f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src)); @@ -2477,8 +2534,9 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC case QShaderDescription::Bool4: f->glUniform4iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src)); break; - // ### more types default: + qWarning("Uniform with buffer binding %d, buffer offset %d has unsupported type %d", + uniform.binding, uniform.offset, uniform.type); break; } } @@ -2944,9 +3002,15 @@ void QRhiGles2::registerUniformIfActive(const QShaderDescription::BlockVariable const QByteArray name = namePrefix + var.name.toUtf8(); uniform.glslLocation = f->glGetUniformLocation(program, name.constData()); if (uniform.glslLocation >= 0) { + if (var.arrayDims.count() > 1) { + qWarning("Array '%s' has more than one dimension. This is not supported.", + qPrintable(var.name)); + return; + } uniform.binding = binding; uniform.offset = uint(baseOffset + var.offset); uniform.size = var.size; + uniform.arrayDim = var.arrayDims.isEmpty() ? 0 : var.arrayDims.first(); dst->append(uniform); } } @@ -2979,11 +3043,6 @@ void QRhiGles2::gatherUniforms(GLuint program, } } } else { - if (!blockMember.arrayDims.isEmpty()) { - qWarning("Arrays are only supported for structs at the moment. '%s' ignored.", - qPrintable(blockMember.name)); - continue; - } registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, dst); } } diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 4a98011d3d..d4f1336c3e 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -252,6 +252,7 @@ struct QGles2UniformDescription int binding; uint offset; int size; + int arrayDim; }; Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 3aa68db585..b6ca40e08b 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -673,12 +673,17 @@ static inline int mapBinding(int binding, BindingType type) { const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex]; - if (map) { - auto it = map->constFind(binding); - if (it != map->cend()) - return type == BindingType::Sampler ? it->second : it->first; - } - return binding; + if (!map) + return binding; // old QShader versions do not have this map, assume 1:1 mapping then + + auto it = map->constFind(binding); + if (it != map->cend()) + return type == BindingType::Sampler ? it->second : it->first; // may be -1, if the resource is inactive + + // Hitting this path is normal too, is not given that the resource (e.g. a + // uniform block) is really present in the shaders for all the stages + // specified by the visibility mask in the QRhiShaderResourceBinding. + return -1; } void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, @@ -712,16 +717,25 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } } if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[VERTEX].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[VERTEX].buffers.feed(nativeBinding, mtlbuf); + res[VERTEX].bufferOffsets.feed(b->binding, offset); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[FRAGMENT].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[FRAGMENT].buffers.feed(nativeBinding, mtlbuf); + res[FRAGMENT].bufferOffsets.feed(b->binding, offset); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[COMPUTE].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[COMPUTE].buffers.feed(nativeBinding, mtlbuf); + res[COMPUTE].bufferOffsets.feed(b->binding, offset); + } } } break; @@ -730,16 +744,28 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[VERTEX].textures.feed(nativeBindingTexture, texD->d->tex); + res[VERTEX].samplers.feed(nativeBindingSampler, samplerD->d->samplerState); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[FRAGMENT].textures.feed(nativeBindingTexture, texD->d->tex); + res[FRAGMENT].samplers.feed(nativeBindingSampler, samplerD->d->samplerState); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex); - res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState); + const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); + const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler); + if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { + res[COMPUTE].textures.feed(nativeBindingTexture, texD->d->tex); + res[COMPUTE].samplers.feed(nativeBindingSampler, samplerD->d->samplerState); + } } } break; @@ -751,12 +777,21 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD { QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex); id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level); - if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) - res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t); - if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) - res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t); - if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) - res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t); + if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { + const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); + if (nativeBinding >= 0) + res[VERTEX].textures.feed(nativeBinding, t); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { + const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); + if (nativeBinding >= 0) + res[FRAGMENT].textures.feed(nativeBinding, t); + } + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); + if (nativeBinding >= 0) + res[COMPUTE].textures.feed(nativeBinding, t); + } } break; case QRhiShaderResourceBinding::BufferLoad: @@ -769,16 +804,25 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD id<MTLBuffer> mtlbuf = bufD->d->buf[0]; uint offset = uint(b->u.sbuf.offset); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[VERTEX].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[VERTEX].buffers.feed(nativeBinding, mtlbuf); + res[VERTEX].bufferOffsets.feed(b->binding, offset); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[FRAGMENT].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[FRAGMENT].buffers.feed(nativeBinding, mtlbuf); + res[FRAGMENT].bufferOffsets.feed(b->binding, offset); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf); - res[COMPUTE].bufferOffsets.feed(b->binding, offset); + const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer); + if (nativeBinding >= 0) { + res[COMPUTE].buffers.feed(nativeBinding, mtlbuf); + res[COMPUTE].bufferOffsets.feed(b->binding, offset); + } } } break; diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index dc6060f882..0b99281f08 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -660,6 +660,13 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v) pair, because combined image samplers may map to two native resources (a texture and a sampler) in some shading languages. In that case the second value refers to the sampler. + + \note The native binding may be -1, in case there is no active binding for + the resource in the shader. (for example, there is a uniform block + declared, but it is not used in the shader code) The map is always + complete, meaning there is an entry for all declared uniform blocks, + storage blocks, image objects, and combined samplers, but the value will be + -1 for those that are not actually referenced in the shader functions. */ /*! |