diff options
Diffstat (limited to 'src/gui/rhi')
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 74 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 10 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p_p.h | 4 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 38 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 227 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 18 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 8 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 26 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p_p.h | 2 | ||||
-rw-r--r-- | src/gui/rhi/qshader.cpp | 2 | ||||
-rw-r--r-- | src/gui/rhi/rhi.pri | 2 |
12 files changed, 327 insertions, 87 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index dbad63c6d1..d7c1607e57 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -494,7 +494,31 @@ QT_BEGIN_NAMESPACE extension. When false, only 16-bit unsigned elements are supported in the index buffer. - \value Compute Indicates that compute shaders are supported. + \value Compute Indicates that compute shaders, image load/store, and + storage buffers are supported. + + \value WideLines Indicates that lines with a width other than 1 are + supported. When reported as not supported, the line width set on the + graphics pipeline state is ignored. This can always be false with some + backends (D3D11, Metal). With Vulkan, the value depends on the + implementation. + + \value VertexShaderPointSize Indicates that the size of rasterized points + set via \c{gl_PointSize} in the vertex shader is taken into account. When + reported as not supported, drawing points with a size other than 1 is not + supported. Setting \c{gl_PointSize} in the shader is still valid then, but + is ignored. (for example, when generating HLSL, the assignment is silently + dropped from the generated code) Note that some APIs (Metal, Vulkan) + require the point size to be set in the shader explicitly whenever drawing + points, even when the size is 1, as they do not automatically default to 1. + + \value BaseVertex Indicates that \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} + supports the \c vertexOffset argument. When reported as not supported, the + vertexOffset value in an indexed draw is ignored. + + \value BaseInstance Indicates that instanced draw commands support the \c + firstInstance argument. When reported as not supported, the firstInstance + value is ignored and the instance ID starts from 0. */ /*! @@ -2575,7 +2599,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( { QRhiShaderResourceBinding b; QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.load() == 1); + Q_ASSERT(d->ref.loadRelaxed() == 1); d->binding = binding; d->stage = stage; d->type = UniformBuffer; @@ -2639,7 +2663,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( { QRhiShaderResourceBinding b; QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.load() == 1); + Q_ASSERT(d->ref.loadRelaxed() == 1); d->binding = binding; d->stage = stage; d->type = SampledTexture; @@ -2661,7 +2685,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad( { QRhiShaderResourceBinding b; QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.load() == 1); + Q_ASSERT(d->ref.loadRelaxed() == 1); d->binding = binding; d->stage = stage; d->type = ImageLoad; @@ -2715,7 +2739,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( { QRhiShaderResourceBinding b; QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b); - Q_ASSERT(d->ref.load() == 1); + Q_ASSERT(d->ref.loadRelaxed() == 1); d->binding = binding; d->stage = stage; d->type = BufferLoad; @@ -3805,6 +3829,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh static_cast<QRhiVulkanNativeHandles *>(importDevice)); break; #else + Q_UNUSED(importDevice); qWarning("This build of Qt has no Vulkan support"); break; #endif @@ -4467,15 +4492,21 @@ void QRhiCommandBuffer::setStencilRef(quint32 refValue) Records a non-indexed draw. The number of vertices is specified in \a vertexCount. For instanced - drawing set \a instanceCount to a value other than 1. \a firstVertex is - the index of the first vertex to draw. \a firstInstance is the instance ID - of the first instance to draw. + drawing set \a instanceCount to a value other than 1. \a firstVertex is the + index of the first vertex to draw. When drawing multiple instances, the + first instance ID is specified by \a firstInstance. + + \note \a firstInstance may not be supported, and is ignored when the + QRhi::BaseInstance feature is reported as not supported. The first ID is + always 0 in that case. \note This function can only be called inside a render pass, meaning between a beginPass() and endPass() call. */ void QRhiCommandBuffer::draw(quint32 vertexCount, - quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) + quint32 instanceCount, + quint32 firstVertex, + quint32 firstInstance) { m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance); } @@ -4493,17 +4524,27 @@ void QRhiCommandBuffer::draw(quint32 vertexCount, \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset} feature will be reported as not-supported. - For instanced drawing set \a instanceCount to a value other than 1. \a - firstInstance is the instance ID of the first instance to draw. + For instanced drawing set \a instanceCount to a value other than 1. When + drawing multiple instances, the first instance ID is specified by \a + firstInstance. + + \note \a firstInstance may not be supported, and is ignored when the + QRhi::BaseInstance feature is reported as not supported. The first ID is + always 0 in that case. - \a vertexOffset is added to the vertex index. + \a vertexOffset (also called \c{base vertex}) is a signed value that is + added to the element index before indexing into the vertex buffer. Support + for this is not always available, and the value is ignored when the feature + QRhi::BaseVertex is reported as unsupported. \note This function can only be called inside a render pass, meaning between a beginPass() and endPass() call. */ void QRhiCommandBuffer::drawIndexed(quint32 indexCount, - quint32 instanceCount, quint32 firstIndex, - qint32 vertexOffset, quint32 firstInstance) + quint32 instanceCount, + quint32 firstIndex, + qint32 vertexOffset, + quint32 firstInstance) { m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); } @@ -5192,10 +5233,11 @@ int QRhi::ubufAlignment() const return d->ubufAlignment(); } +static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0); + QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId() { - static QRhiGlobalObjectIdGenerator inst; - return ++inst.counter; + return counter.fetchAndAddRelaxed(1) + 1; } bool QRhiPassResourceTracker::isEmpty() const diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 0d296d370c..df30817ef4 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1068,6 +1068,9 @@ public: int sampleCount() const { return m_sampleCount; } void setSampleCount(int s) { m_sampleCount = s; } + float lineWidth() const { return m_lineWidth; } + void setLineWidth(float width) { m_lineWidth = width; } + QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; } void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; } @@ -1098,6 +1101,7 @@ protected: quint32 m_stencilReadMask = 0xFF; quint32 m_stencilWriteMask = 0xFF; int m_sampleCount = 1; + float m_lineWidth = 1.0f; QVector<QRhiShaderStage> m_shaderStages; QRhiVertexInputLayout m_vertexInputLayout; QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr; @@ -1312,7 +1316,11 @@ public: NPOTTextureRepeat, RedOrAlpha8IsRed, ElementIndexUint, - Compute + Compute, + WideLines, + VertexShaderPointSize, + BaseVertex, + BaseInstance }; enum BeginFrameFlag { diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 4fd01d3ef2..83d521f441 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -52,7 +52,6 @@ #include "qrhiprofiler_p_p.h" #include <QBitArray> #include <QAtomicInt> -#include <QAtomicInteger> QT_BEGIN_NAMESPACE @@ -484,9 +483,6 @@ public: using Type = quint32; #endif static Type newId(); - -private: - QAtomicInteger<Type> counter; }; class QRhiPassResourceTracker diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 7d9c934c18..a8a490eb5c 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -39,6 +39,7 @@ #include <QWindow> #include <QOperatingSystemVersion> #include <qmath.h> +#include <private/qsystemlibrary_p.h> #include <d3dcompiler.h> #include <comdef.h> @@ -150,7 +151,8 @@ static QString comErrorMessage(HRESULT hr) return result; } -static inline uint aligned(uint v, uint byteAlign) +template <class Int> +static inline Int aligned(Int v, Int byteAlign) { return (v + byteAlign - 1) & ~(byteAlign - 1); } @@ -377,6 +379,14 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::Compute: return true; + case QRhi::WideLines: + return false; + case QRhi::VertexShaderPointSize: + return false; + case QRhi::BaseVertex: + return true; + case QRhi::BaseInstance: + return true; default: Q_UNREACHABLE(); return false; @@ -595,7 +605,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind for (int i = 0; i < dynamicOffsetCount; ++i) { const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]); const uint binding = dynOfs.first; - Q_ASSERT(aligned(dynOfs.second, 256) == dynOfs.second); + Q_ASSERT(aligned(dynOfs.second, quint32(256)) == dynOfs.second); const uint offsetInConstants = dynOfs.second / 16; *p++ = binding; *p++ = offsetInConstants; @@ -1471,6 +1481,8 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb, cbD->recordingPass = QD3D11CommandBuffer::RenderPass; cbD->currentTarget = rt; + + cbD->resetCachedShaderResourceState(); } void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -1547,6 +1559,8 @@ void QRhiD3D11::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch cbD->commands.append(cmd); cbD->recordingPass = QD3D11CommandBuffer::ComputePass; + + cbD->resetCachedShaderResourceState(); } void QRhiD3D11::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -3205,6 +3219,18 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op) } } +static pD3DCompile resolveD3DCompile() +{ + for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) { + QSystemLibrary library(libraryName); + if (library.load()) { + if (auto symbol = library.resolve("D3DCompile")) + return reinterpret_cast<pD3DCompile>(symbol); + } + } + return nullptr; +} + static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error) { QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant }); @@ -3242,9 +3268,15 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian return QByteArray(); } + static const pD3DCompile d3dCompile = resolveD3DCompile(); + if (d3dCompile == nullptr) { + qWarning("Unable to resolve function D3DCompile()"); + return QByteArray(); + } + ID3DBlob *bytecode = nullptr; ID3DBlob *errors = nullptr; - HRESULT hr = D3DCompile(hlslSource.shader().constData(), hlslSource.shader().size(), + HRESULT hr = d3dCompile(hlslSource.shader().constData(), hlslSource.shader().size(), nullptr, nullptr, nullptr, hlslSource.entryPoint().constData(), target, 0, 0, &bytecode, &errors); if (FAILED(hr) || !bytecode) { diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 688f79b3b7..34c9ff70f8 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -482,6 +482,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer currentGraphicsPipeline = nullptr; currentComputePipeline = nullptr; currentPipelineGeneration = 0; + resetCachedShaderResourceState(); + } + void resetCachedShaderResourceState() { currentGraphicsSrb = nullptr; currentComputeSrb = nullptr; currentSrbGeneration = 0; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 7c40a36701..22cb030c27 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -175,14 +175,34 @@ QT_BEGIN_NAMESPACE #define GL_DEPTH_COMPONENT16 0x81A5 #endif +#ifndef GL_DEPTH_COMPONENT24 +#define GL_DEPTH_COMPONENT24 0x81A6 +#endif + #ifndef GL_DEPTH_COMPONENT32F #define GL_DEPTH_COMPONENT32F 0x8CAC #endif +#ifndef GL_STENCIL_INDEX +#define GL_STENCIL_INDEX 0x1901 +#endif + +#ifndef GL_STENCIL_INDEX8 +#define GL_STENCIL_INDEX8 0x8D48 +#endif + #ifndef GL_DEPTH24_STENCIL8 #define GL_DEPTH24_STENCIL8 0x88F0 #endif +#ifndef GL_DEPTH_STENCIL_ATTACHMENT +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#endif + +#ifndef GL_DEPTH_STENCIL +#define GL_DEPTH_STENCIL 0x84F9 +#endif + #ifndef GL_PRIMITIVE_RESTART_FIXED_INDEX #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #endif @@ -394,10 +414,19 @@ bool QRhiGles2::create(QRhi::Flags flags) caps.floatFormats = caps.ctxMajor >= 3; caps.depthTexture = caps.ctxMajor >= 3; caps.packedDepthStencil = f->hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil); +#ifdef Q_OS_WASM + caps.needsDepthStencilCombinedAttach = true; +#else + caps.needsDepthStencilCombinedAttach = false; +#endif caps.srgbCapableDefaultFramebuffer = f->hasOpenGLExtension(QOpenGLExtensions::SRGBFrameBuffer); caps.coreProfile = actualFormat.profile() == QSurfaceFormat::CoreProfile; caps.uniformBuffers = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 1); caps.elementIndexUint = f->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint); + caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24); + caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats); + caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3); + caps.baseVertex = caps.ctxMajor >= 3 && caps.ctxMinor >= 2; nativeHandlesStruct.context = ctx; @@ -470,6 +499,43 @@ int QRhiGles2::effectiveSampleCount(int sampleCount) const return s; } +static inline bool isPowerOfTwo(int x) +{ + // Assumption: x >= 1 + return x == (x & -x); +} + +QSize QRhiGles2::safeTextureSize(const QSize &pixelSize) const +{ + QSize size = pixelSize.isEmpty() ? QSize(1, 1) : pixelSize; + + if (!caps.npotTexture) { + if (!isPowerOfTwo(size.width())) { + qWarning("Texture width %d is not a power of two, adjusting", + size.width()); + size.setWidth(qNextPowerOfTwo(size.width())); + } + if (!isPowerOfTwo(size.height())) { + qWarning("Texture height %d is not a power of two, adjusting", + size.height()); + size.setHeight(qNextPowerOfTwo(size.height())); + } + } + + if (size.width() > caps.maxTextureSize) { + qWarning("Texture width %d exceeds maximum width %d, adjusting", + size.width(), caps.maxTextureSize); + size.setWidth(caps.maxTextureSize); + } + if (size.height() > caps.maxTextureSize) { + qWarning("Texture height %d exceeds maximum height %d, adjusting", + size.height(), caps.maxTextureSize); + size.setHeight(caps.maxTextureSize); + } + + return size; +} + QRhiSwapChain *QRhiGles2::createSwapChain() { return new QGles2SwapChain(this); @@ -601,7 +667,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const case QRhi::Timestamps: return false; case QRhi::Instancing: - return false; + return caps.instancing; case QRhi::CustomInstanceStepRate: return false; case QRhi::PrimitiveRestart: @@ -618,6 +684,14 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const return caps.elementIndexUint; case QRhi::Compute: return false; + case QRhi::WideLines: + return true; + case QRhi::VertexShaderPointSize: + return true; + case QRhi::BaseVertex: + return caps.baseVertex; + case QRhi::BaseInstance: + return false; // not in ES 3.2, so won't bother default: Q_UNREACHABLE(); return false; @@ -865,8 +939,6 @@ void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) { - Q_UNUSED(instanceCount); // no instancing - Q_UNUSED(firstInstance); QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass); @@ -875,15 +947,14 @@ void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount, cmd.args.draw.ps = cbD->currentPipeline; cmd.args.draw.vertexCount = vertexCount; cmd.args.draw.firstVertex = firstVertex; + cmd.args.draw.instanceCount = instanceCount; + cmd.args.draw.baseInstance = firstInstance; cbD->commands.append(cmd); } void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) { - Q_UNUSED(instanceCount); // no instancing - Q_UNUSED(firstInstance); - Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass); @@ -892,6 +963,9 @@ void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, cmd.args.drawIndexed.ps = cbD->currentPipeline; cmd.args.drawIndexed.indexCount = indexCount; cmd.args.drawIndexed.firstIndex = firstIndex; + cmd.args.drawIndexed.instanceCount = instanceCount; + cmd.args.drawIndexed.baseInstance = firstInstance; + cmd.args.drawIndexed.baseVertex = vertexOffset; cbD->commands.append(cmd); } @@ -1545,13 +1619,14 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) const QVector<QRhiVertexInputBinding> bindings = psD->m_vertexInputLayout.bindings(); const QVector<QRhiVertexInputAttribute> attributes = psD->m_vertexInputLayout.attributes(); for (const QRhiVertexInputAttribute &a : attributes) { - if (a.binding() != cmd.args.bindVertexBuffer.binding) + const int bindingIdx = a.binding(); + if (bindingIdx != cmd.args.bindVertexBuffer.binding) continue; // we do not support more than one vertex buffer f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer); - const int stride = bindings[a.binding()].stride(); + const int stride = bindings[bindingIdx].stride(); int size = 1; GLenum type = GL_FLOAT; bool normalize = false; @@ -1590,10 +1665,17 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) default: break; } + + const int locationIdx = a.location(); quint32 ofs = a.offset() + cmd.args.bindVertexBuffer.offset; - f->glVertexAttribPointer(a.location(), size, type, normalize, stride, + f->glVertexAttribPointer(locationIdx, size, type, normalize, stride, reinterpret_cast<const GLvoid *>(quintptr(ofs))); - f->glEnableVertexAttribArray(a.location()); + f->glEnableVertexAttribArray(locationIdx); + if (bindings[bindingIdx].classification() == QRhiVertexInputBinding::PerInstance + && caps.instancing) + { + f->glVertexAttribDivisor(locationIdx, bindings[bindingIdx].instanceStepRate()); + } } } else { qWarning("No graphics pipeline active for setVertexInput; ignored"); @@ -1609,21 +1691,53 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) case QGles2CommandBuffer::Command::Draw: { QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.draw.ps); - if (psD) - f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount); - else + if (psD) { + if (cmd.args.draw.instanceCount == 1 || !caps.instancing) { + f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount); + } else { + f->glDrawArraysInstanced(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount, + cmd.args.draw.instanceCount); + } + } else { qWarning("No graphics pipeline active for draw; ignored"); + } } break; case QGles2CommandBuffer::Command::DrawIndexed: { QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.drawIndexed.ps); if (psD) { - quint32 ofs = cmd.args.drawIndexed.firstIndex * indexStride + indexOffset; - f->glDrawElements(psD->drawMode, - cmd.args.drawIndexed.indexCount, - indexType, - reinterpret_cast<const GLvoid *>(quintptr(ofs))); + const GLvoid *ofs = reinterpret_cast<const GLvoid *>( + quintptr(cmd.args.drawIndexed.firstIndex * indexStride + indexOffset)); + if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) { + if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) { + f->glDrawElementsBaseVertex(psD->drawMode, + cmd.args.drawIndexed.indexCount, + indexType, + ofs, + cmd.args.drawIndexed.baseVertex); + } else { + f->glDrawElements(psD->drawMode, + cmd.args.drawIndexed.indexCount, + indexType, + ofs); + } + } else { + if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) { + f->glDrawElementsInstancedBaseVertex(psD->drawMode, + cmd.args.drawIndexed.indexCount, + indexType, + ofs, + cmd.args.drawIndexed.instanceCount, + cmd.args.drawIndexed.baseVertex); + } else { + f->glDrawElementsInstanced(psD->drawMode, + cmd.args.drawIndexed.indexCount, + indexType, + ofs, + cmd.args.drawIndexed.instanceCount); + } + } } else { qWarning("No graphics pipeline active for drawIndexed; ignored"); } @@ -1849,6 +1963,9 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps) f->glDisable(GL_STENCIL_TEST); } + if (psD->topology() == QRhiGraphicsPipeline::Lines || psD->topology() == QRhiGraphicsPipeline::LineStrip) + f->glLineWidth(psD->m_lineWidth); + f->glUseProgram(psD->program); } @@ -2242,43 +2359,51 @@ bool QGles2RenderBuffer::build() qWarning("RenderBuffer: UsedWithSwapChainOnly is meaningless in combination with Color"); } - if (m_pixelSize.isEmpty()) - return false; - if (!rhiD->ensureContext()) return false; rhiD->f->glGenRenderbuffers(1, &renderbuffer); rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + const QSize size = rhiD->safeTextureSize(m_pixelSize); + switch (m_type) { case QRhiRenderBuffer::DepthStencil: if (rhiD->caps.msaaRenderBuffer && samples > 1) { - rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, - m_pixelSize.width(), m_pixelSize.height()); + const GLenum storage = rhiD->caps.needsDepthStencilCombinedAttach ? GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8; + rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, + size.width(), size.height()); + stencilRenderbuffer = 0; + } else if (rhiD->caps.packedDepthStencil || rhiD->caps.needsDepthStencilCombinedAttach) { + const GLenum storage = rhiD->caps.needsDepthStencilCombinedAttach ? GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8; + rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, storage, + size.width(), size.height()); + stencilRenderbuffer = 0; } else { - if (rhiD->caps.packedDepthStencil) { - rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - m_pixelSize.width(), m_pixelSize.height()); - stencilRenderbuffer = 0; - } else { - rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_ATTACHMENT, - m_pixelSize.width(), m_pixelSize.height()); - rhiD->f->glGenRenderbuffers(1, &stencilRenderbuffer); - rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderbuffer); - rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_ATTACHMENT, - m_pixelSize.width(), m_pixelSize.height()); + GLenum depthStorage = GL_DEPTH_COMPONENT; + if (rhiD->caps.gles) { + if (rhiD->caps.depth24) + depthStorage = GL_DEPTH_COMPONENT24; + else + depthStorage = GL_DEPTH_COMPONENT16; // plain ES 2.0 only has this } + const GLenum stencilStorage = rhiD->caps.gles ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; + rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, depthStorage, + size.width(), size.height()); + rhiD->f->glGenRenderbuffers(1, &stencilRenderbuffer); + rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderbuffer); + rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, stencilStorage, + size.width(), size.height()); } QRHI_PROF_F(newRenderBuffer(this, false, false, samples)); break; case QRhiRenderBuffer::Color: if (rhiD->caps.msaaRenderBuffer && samples > 1) rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, - m_pixelSize.width(), m_pixelSize.height()); + size.width(), size.height()); else - rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, - m_pixelSize.width(), m_pixelSize.height()); + rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA4, + size.width(), size.height()); QRHI_PROF_F(newRenderBuffer(this, false, false, samples)); break; default: @@ -2328,12 +2453,6 @@ void QGles2Texture::release() rhiD->unregisterResource(this); } -static inline bool isPowerOfTwo(int x) -{ - // Assumption: x >= 1 - return x == (x & -x); -} - bool QGles2Texture::prepareBuild(QSize *adjustedSize) { if (texture) @@ -2343,9 +2462,7 @@ bool QGles2Texture::prepareBuild(QSize *adjustedSize) if (!rhiD->ensureContext()) return false; - QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize; - if (!rhiD->caps.npotTexture && (!isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()))) - size = QSize(qNextPowerOfTwo(size.width()), qNextPowerOfTwo(size.height())); + const QSize size = rhiD->safeTextureSize(m_pixelSize); const bool isCube = m_flags.testFlag(CubeMap); const bool hasMipMaps = m_flags.testFlag(MipMapped); @@ -2660,11 +2777,19 @@ bool QGles2TextureRenderTarget::build() if (hasDepthStencil) { if (m_desc.depthStencilBuffer()) { QGles2RenderBuffer *depthRbD = QRHI_RES(QGles2RenderBuffer, m_desc.depthStencilBuffer()); - rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbD->renderbuffer); - if (depthRbD->stencilRenderbuffer) - rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbD->stencilRenderbuffer); - else // packed - rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbD->renderbuffer); + if (rhiD->caps.needsDepthStencilCombinedAttach) { + rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + depthRbD->renderbuffer); + } else { + rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + depthRbD->renderbuffer); + if (depthRbD->stencilRenderbuffer) + rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + depthRbD->stencilRenderbuffer); + else // packed + rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + depthRbD->renderbuffer); + } if (d.colorAttCount == 0) { d.pixelSize = depthRbD->pixelSize(); d.sampleCount = depthRbD->samples; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index fe74e2e75b..d6682977ff 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -324,11 +324,16 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer QRhiGraphicsPipeline *ps; quint32 vertexCount; quint32 firstVertex; + quint32 instanceCount; + quint32 baseInstance; } draw; struct { QRhiGraphicsPipeline *ps; quint32 indexCount; quint32 firstIndex; + quint32 instanceCount; + quint32 baseInstance; + qint32 baseVertex; } drawIndexed; struct { QRhiGraphicsPipeline *ps; @@ -611,6 +616,7 @@ public: QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD, bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr); int effectiveSampleCount(int sampleCount) const; + QSize safeTextureSize(const QSize &size) const; QOpenGLContext *ctx = nullptr; bool importedContext = false; @@ -638,10 +644,15 @@ public: floatFormats(false), depthTexture(false), packedDepthStencil(false), + needsDepthStencilCombinedAttach(false), srgbCapableDefaultFramebuffer(false), coreProfile(false), uniformBuffers(false), - elementIndexUint(false) + elementIndexUint(false), + depth24(false), + rgba8Format(false), + instancing(false), + baseVertex(false) { } int ctxMajor; int ctxMinor; @@ -662,10 +673,15 @@ public: uint floatFormats : 1; uint depthTexture : 1; uint packedDepthStencil : 1; + uint needsDepthStencilCombinedAttach : 1; uint srgbCapableDefaultFramebuffer : 1; uint coreProfile : 1; uint uniformBuffers : 1; uint elementIndexUint : 1; + uint depth24 : 1; + uint rgba8Format : 1; + uint instancing : 1; + uint baseVertex : 1; } caps; QGles2SwapChain *currentSwapChain = nullptr; QVector<GLint> supportedCompressedFormats; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 214374e0c6..fa537a504b 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -523,6 +523,14 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::Compute: return true; + case QRhi::WideLines: + return false; + case QRhi::VertexShaderPointSize: + return true; + case QRhi::BaseVertex: + return true; + case QRhi::BaseInstance: + return true; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index f6ecd7c00e..7c4eeaf226 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -489,6 +489,9 @@ bool QRhiVulkan::create(QRhi::Flags flags) // elsewhere states that the minimum bufferOffset is 4... texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment); + f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures); + hasWideLines = physDevFeatures.wideLines; + if (!importedAllocator) { VmaVulkanFunctions afuncs; afuncs.vkGetPhysicalDeviceProperties = wrap_vkGetPhysicalDeviceProperties; @@ -3489,24 +3492,21 @@ QMatrix4x4 QRhiVulkan::clipSpaceCorrMatrix() const bool QRhiVulkan::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const { - VkPhysicalDeviceFeatures features; - f->vkGetPhysicalDeviceFeatures(physDev, &features); - // Note that with some SDKs the validation layer gives an odd warning about // BC not being supported, even when our check here succeeds. Not much we // can do about that. if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) { - if (!features.textureCompressionBC) + if (!physDevFeatures.textureCompressionBC) return false; } if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) { - if (!features.textureCompressionETC2) + if (!physDevFeatures.textureCompressionETC2) return false; } if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) { - if (!features.textureCompressionASTC_LDR) + if (!physDevFeatures.textureCompressionASTC_LDR) return false; } @@ -3545,6 +3545,14 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::Compute: return hasCompute; + case QRhi::WideLines: + return hasWideLines; + case QRhi::VertexShaderPointSize: + return true; + case QRhi::BaseVertex: + return true; + case QRhi::BaseInstance: + return true; default: Q_UNREACHABLE(); return false; @@ -4059,7 +4067,7 @@ void QRhiVulkan::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) } void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount, - quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) + quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) { QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass); @@ -4074,7 +4082,7 @@ void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount, } void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, - quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) + quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) { QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass); @@ -5612,7 +5620,7 @@ bool QVkGraphicsPipeline::build() rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rastInfo.cullMode = toVkCullMode(m_cullMode); rastInfo.frontFace = toVkFrontFace(m_frontFace); - rastInfo.lineWidth = 1.0f; + rastInfo.lineWidth = rhiD->hasWideLines ? m_lineWidth : 1.0f; pipelineInfo.pRasterizationState = &rastInfo; VkPipelineMultisampleStateCreateInfo msInfo; diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index cec9016603..31e0eaa585 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -783,9 +783,11 @@ public: QVkAllocator allocator = nullptr; QVulkanFunctions *f = nullptr; QVulkanDeviceFunctions *df = nullptr; + VkPhysicalDeviceFeatures physDevFeatures; VkPhysicalDeviceProperties physDevProperties; VkDeviceSize ubufAlign; VkDeviceSize texbufAlign; + bool hasWideLines = false; bool debugMarkersAvailable = false; bool vertexAttribDivisorAvailable = false; diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 4676ec3f5b..9098180f69 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -389,7 +389,7 @@ QShader QShader::fromSerialized(const QByteArray &data) QShader bs; QShaderPrivate *d = QShaderPrivate::get(&bs); - Q_ASSERT(d->ref.load() == 1); // must be detached + Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached int intVal; ds >> intVal; if (intVal != QSB_VERSION) diff --git a/src/gui/rhi/rhi.pri b/src/gui/rhi/rhi.pri index d8607f1024..4297a5602b 100644 --- a/src/gui/rhi/rhi.pri +++ b/src/gui/rhi/rhi.pri @@ -40,7 +40,7 @@ win32 { SOURCES += \ rhi/qrhid3d11.cpp - LIBS += -ld3d11 -ldxgi -ldxguid -ld3dcompiler + LIBS += -ld3d11 -ldxgi -ldxguid } # darwin { |