summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp74
-rw-r--r--src/gui/rhi/qrhi_p.h10
-rw-r--r--src/gui/rhi/qrhi_p_p.h4
-rw-r--r--src/gui/rhi/qrhid3d11.cpp38
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h3
-rw-r--r--src/gui/rhi/qrhigles2.cpp227
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h18
-rw-r--r--src/gui/rhi/qrhimetal.mm8
-rw-r--r--src/gui/rhi/qrhivulkan.cpp26
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h2
-rw-r--r--src/gui/rhi/qshader.cpp2
-rw-r--r--src/gui/rhi/rhi.pri2
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 {