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:
Laszlo Agocs 2019-07-01 11:18:10 +02:00
parent c955426945
commit 493ce2f3d4
6 changed files with 833 additions and 255 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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,