rhi: gl: Add support for compute
...and storage buffers and images. Change-Id: If38a51322e3187088a13cf4e9b88cb40c8af8621 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
c955426945
commit
493ce2f3d4
@ -5337,4 +5337,32 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
|
||||
m_textures.append(t);
|
||||
}
|
||||
|
||||
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||
{
|
||||
// pick the earlier stage (as this is going to be dstAccessMask)
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||
return QRhiPassResourceTracker::BufVertexStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||
return QRhiPassResourceTracker::BufFragmentStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||
return QRhiPassResourceTracker::BufComputeStage;
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return QRhiPassResourceTracker::BufVertexStage;
|
||||
}
|
||||
|
||||
QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||
{
|
||||
// pick the earlier stage (as this is going to be dstAccessMask)
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||
return QRhiPassResourceTracker::TexVertexStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||
return QRhiPassResourceTracker::TexFragmentStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||
return QRhiPassResourceTracker::TexComputeStage;
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return QRhiPassResourceTracker::TexVertexStage;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -553,6 +553,9 @@ public:
|
||||
};
|
||||
const QVector<Texture> *textures() const { return &m_textures; }
|
||||
|
||||
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
|
||||
|
||||
private:
|
||||
QVector<Buffer> m_buffers;
|
||||
QVector<Texture> m_textures;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -66,8 +66,22 @@ struct QGles2Buffer : public QRhiBuffer
|
||||
bool build() override;
|
||||
|
||||
GLuint buffer = 0;
|
||||
GLenum target;
|
||||
GLenum targetForDataOps;
|
||||
QByteArray ubuf;
|
||||
enum Access {
|
||||
AccessNone,
|
||||
AccessVertex,
|
||||
AccessIndex,
|
||||
AccessUniform,
|
||||
AccessStorageRead,
|
||||
AccessStorageWrite,
|
||||
AccessStorageReadWrite,
|
||||
AccessUpdate
|
||||
};
|
||||
struct UsageState {
|
||||
Access access;
|
||||
};
|
||||
UsageState usageState;
|
||||
friend class QRhiGles2;
|
||||
};
|
||||
|
||||
@ -127,12 +141,27 @@ struct QGles2Texture : public QRhiTexture
|
||||
bool owns = true;
|
||||
GLenum target;
|
||||
GLenum glintformat;
|
||||
GLenum glsizedintformat;
|
||||
GLenum glformat;
|
||||
GLenum gltype;
|
||||
QGles2SamplerData samplerState;
|
||||
bool specified = false;
|
||||
int mipLevelCount = 0;
|
||||
QRhiGles2TextureNativeHandles nativeHandlesStruct;
|
||||
enum Access {
|
||||
AccessNone,
|
||||
AccessSample,
|
||||
AccessFramebuffer,
|
||||
AccessStorageRead,
|
||||
AccessStorageWrite,
|
||||
AccessStorageReadWrite,
|
||||
AccessUpdate,
|
||||
AccessRead
|
||||
};
|
||||
struct UsageState {
|
||||
Access access;
|
||||
};
|
||||
UsageState usageState;
|
||||
|
||||
uint generation = 0;
|
||||
friend class QRhiGles2;
|
||||
@ -213,6 +242,25 @@ struct QGles2ShaderResourceBindings : public QRhiShaderResourceBindings
|
||||
friend class QRhiGles2;
|
||||
};
|
||||
|
||||
struct QGles2UniformDescription
|
||||
{
|
||||
QShaderDescription::VariableType type;
|
||||
int glslLocation;
|
||||
int binding;
|
||||
uint offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_MOVABLE_TYPE);
|
||||
|
||||
struct QGles2SamplerDescription
|
||||
{
|
||||
int glslLocation;
|
||||
int binding;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QGles2SamplerDescription, Q_MOVABLE_TYPE);
|
||||
|
||||
struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
|
||||
{
|
||||
QGles2GraphicsPipeline(QRhiImplementation *rhi);
|
||||
@ -222,38 +270,24 @@ struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
|
||||
|
||||
GLuint program = 0;
|
||||
GLenum drawMode = GL_TRIANGLES;
|
||||
QShaderDescription vsDesc;
|
||||
QShaderDescription fsDesc;
|
||||
bool canUseUniformBuffers = false;
|
||||
|
||||
struct Uniform {
|
||||
QShaderDescription::VariableType type;
|
||||
int glslLocation;
|
||||
int binding;
|
||||
uint offset;
|
||||
int size;
|
||||
};
|
||||
QVector<Uniform> uniforms;
|
||||
|
||||
struct Sampler {
|
||||
int glslLocation;
|
||||
int binding;
|
||||
};
|
||||
QVector<Sampler> samplers;
|
||||
|
||||
QVector<QGles2UniformDescription> uniforms;
|
||||
QVector<QGles2SamplerDescription> samplers;
|
||||
uint generation = 0;
|
||||
friend class QRhiGles2;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Uniform, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Sampler, Q_MOVABLE_TYPE);
|
||||
|
||||
struct QGles2ComputePipeline : public QRhiComputePipeline
|
||||
{
|
||||
QGles2ComputePipeline(QRhiImplementation *rhi);
|
||||
~QGles2ComputePipeline();
|
||||
void release() override;
|
||||
bool build() override;
|
||||
|
||||
GLuint program = 0;
|
||||
QVector<QGles2UniformDescription> uniforms;
|
||||
QVector<QGles2SamplerDescription> samplers;
|
||||
uint generation = 0;
|
||||
friend class QRhiGles2;
|
||||
};
|
||||
|
||||
struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
@ -286,7 +320,11 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
CompressedImage,
|
||||
CompressedSubImage,
|
||||
BlitFromRenderbuffer,
|
||||
GenMip
|
||||
GenMip,
|
||||
BindComputePipeline,
|
||||
Dispatch,
|
||||
BarriersForPass,
|
||||
Barrier
|
||||
};
|
||||
Cmd cmd;
|
||||
|
||||
@ -339,7 +377,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
QRhiGraphicsPipeline *ps;
|
||||
} bindGraphicsPipeline;
|
||||
struct {
|
||||
QRhiGraphicsPipeline *ps;
|
||||
QRhiGraphicsPipeline *maybeGraphicsPs;
|
||||
QRhiComputePipeline *maybeComputePs;
|
||||
QRhiShaderResourceBindings *srb;
|
||||
int dynamicOffsetCount;
|
||||
uint dynamicOffsetPairs[MAX_UBUF_BINDINGS * 2]; // binding, offsetInConstants
|
||||
@ -436,6 +475,20 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
GLenum target;
|
||||
GLuint texture;
|
||||
} genMip;
|
||||
struct {
|
||||
QRhiComputePipeline *ps;
|
||||
} bindComputePipeline;
|
||||
struct {
|
||||
GLuint x;
|
||||
GLuint y;
|
||||
GLuint z;
|
||||
} dispatch;
|
||||
struct {
|
||||
int trackerIndex;
|
||||
} barriersForPass;
|
||||
struct {
|
||||
GLbitfield barriers;
|
||||
} barrier;
|
||||
} args;
|
||||
};
|
||||
|
||||
@ -446,11 +499,16 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
};
|
||||
|
||||
QVector<Command> commands;
|
||||
QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
|
||||
int currentPassResTrackerIndex;
|
||||
|
||||
PassType recordingPass;
|
||||
QRhiRenderTarget *currentTarget;
|
||||
QRhiGraphicsPipeline *currentPipeline;
|
||||
QRhiGraphicsPipeline *currentGraphicsPipeline;
|
||||
QRhiComputePipeline *currentComputePipeline;
|
||||
uint currentPipelineGeneration;
|
||||
QRhiShaderResourceBindings *currentSrb;
|
||||
QRhiShaderResourceBindings *currentGraphicsSrb;
|
||||
QRhiShaderResourceBindings *currentComputeSrb;
|
||||
uint currentSrbGeneration;
|
||||
|
||||
QVector<QByteArray> dataRetainPool;
|
||||
@ -467,6 +525,12 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
}
|
||||
void resetCommands() {
|
||||
commands.clear();
|
||||
// beginExternal() can lead to calling resetCommands() inside a pass,
|
||||
// hence the condition
|
||||
if (recordingPass == NoPass) {
|
||||
passResTrackers.clear();
|
||||
currentPassResTrackerIndex = -1;
|
||||
}
|
||||
dataRetainPool.clear();
|
||||
imageRetainPool.clear();
|
||||
}
|
||||
@ -477,9 +541,11 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||
resetCachedState();
|
||||
}
|
||||
void resetCachedState() {
|
||||
currentPipeline = nullptr;
|
||||
currentGraphicsPipeline = nullptr;
|
||||
currentComputePipeline = nullptr;
|
||||
currentPipelineGeneration = 0;
|
||||
currentSrb = nullptr;
|
||||
currentGraphicsSrb = nullptr;
|
||||
currentComputeSrb = nullptr;
|
||||
currentSrbGeneration = 0;
|
||||
}
|
||||
};
|
||||
@ -606,17 +672,35 @@ public:
|
||||
bool ensureContext(QSurface *surface = nullptr) const;
|
||||
void executeDeferredReleases();
|
||||
QRhi::FrameOpResult flushCommandBuffer();
|
||||
void trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access);
|
||||
void trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Texture::Access access);
|
||||
void enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cbD,
|
||||
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
|
||||
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
|
||||
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
|
||||
QGles2Buffer *bufD,
|
||||
QRhiPassResourceTracker::BufferAccess access,
|
||||
QRhiPassResourceTracker::BufferStage stage);
|
||||
void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
|
||||
QGles2Texture *texD,
|
||||
QRhiPassResourceTracker::TextureAccess access,
|
||||
QRhiPassResourceTracker::TextureStage stage);
|
||||
void executeCommandBuffer(QRhiCommandBuffer *cb);
|
||||
void executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps);
|
||||
void bindShaderResources(QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb,
|
||||
void bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
|
||||
QRhiShaderResourceBindings *srb,
|
||||
const uint *dynOfsPairs, int dynOfsCount);
|
||||
QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD,
|
||||
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
|
||||
int effectiveSampleCount(int sampleCount) const;
|
||||
QSize safeTextureSize(const QSize &size) const;
|
||||
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
|
||||
QShaderDescription *desc, int *glslVersionUsed);
|
||||
bool linkProgram(GLuint program);
|
||||
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
||||
QVector<QGles2UniformDescription> *dst);
|
||||
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
|
||||
QVector<QGles2SamplerDescription> *dst);
|
||||
|
||||
QOpenGLContext *ctx = nullptr;
|
||||
bool importedContext = false;
|
||||
@ -652,7 +736,8 @@ public:
|
||||
depth24(false),
|
||||
rgba8Format(false),
|
||||
instancing(false),
|
||||
baseVertex(false)
|
||||
baseVertex(false),
|
||||
compute(false)
|
||||
{ }
|
||||
int ctxMajor;
|
||||
int ctxMinor;
|
||||
@ -682,6 +767,7 @@ public:
|
||||
uint rgba8Format : 1;
|
||||
uint instancing : 1;
|
||||
uint baseVertex : 1;
|
||||
uint compute : 1;
|
||||
} caps;
|
||||
QGles2SwapChain *currentSwapChain = nullptr;
|
||||
QVector<GLint> supportedCompressedFormats;
|
||||
|
@ -3664,34 +3664,6 @@ void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
|
||||
psD->lastActiveFrameSlot = currentFrameSlot;
|
||||
}
|
||||
|
||||
QRhiPassResourceTracker::BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||
{
|
||||
// pick the earlier stage (as this is going to be dstAccessMask)
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||
return QRhiPassResourceTracker::BufVertexStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||
return QRhiPassResourceTracker::BufFragmentStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||
return QRhiPassResourceTracker::BufComputeStage;
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return QRhiPassResourceTracker::BufVertexStage;
|
||||
}
|
||||
|
||||
QRhiPassResourceTracker::TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
|
||||
{
|
||||
// pick the earlier stage (as this is going to be dstAccessMask)
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||
return QRhiPassResourceTracker::TexVertexStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||
return QRhiPassResourceTracker::TexFragmentStage;
|
||||
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||
return QRhiPassResourceTracker::TexComputeStage;
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return QRhiPassResourceTracker::TexVertexStage;
|
||||
}
|
||||
|
||||
void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
|
||||
int dynamicOffsetCount,
|
||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
||||
@ -3747,7 +3719,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
bufD->lastActiveFrameSlot = currentFrameSlot;
|
||||
trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
|
||||
QRhiPassResourceTracker::BufUniformRead,
|
||||
toPassTrackerBufferStage(b->stage));
|
||||
QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
|
||||
|
||||
// Check both the "local" id (the generation counter) and the
|
||||
// global id. The latter is relevant when a newly allocated
|
||||
@ -3768,7 +3740,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
samplerD->lastActiveFrameSlot = currentFrameSlot;
|
||||
trackedRegisterTexture(&passResTracker, texD,
|
||||
QRhiPassResourceTracker::TexSample,
|
||||
toPassTrackerTextureStage(b->stage));
|
||||
QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
|
||||
|
||||
if (texD->generation != bd.stex.texGeneration
|
||||
|| texD->m_id != bd.stex.texId
|
||||
@ -3801,7 +3773,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
access = QRhiPassResourceTracker::TexStorageLoadStore;
|
||||
trackedRegisterTexture(&passResTracker, texD,
|
||||
access,
|
||||
toPassTrackerTextureStage(b->stage));
|
||||
QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
|
||||
|
||||
if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
|
||||
rewriteDescSet = true;
|
||||
@ -3832,7 +3804,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
|
||||
access = QRhiPassResourceTracker::BufStorageLoadStore;
|
||||
trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
|
||||
access,
|
||||
toPassTrackerBufferStage(b->stage));
|
||||
QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
|
||||
|
||||
if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
|
||||
rewriteDescSet = true;
|
||||
|
@ -146,7 +146,7 @@ void Window::customInit()
|
||||
d.ubuf->build();
|
||||
d.releasePool << d.ubuf;
|
||||
|
||||
qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0;
|
||||
qint32 flip = 0; // regardless of isYUpInFramebuffer() since the input is not flipped so the end result is good for GL too
|
||||
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
|
Loading…
Reference in New Issue
Block a user