rhi: Add the basic infrastructure for geometry shader support

.. but this will only be supported on Vulkan, OpenGL 3.2+, and Open GL
ES 3.2+ for the time being.

The situation is:

- Vulkan is working.  qsb accepts .geom files already, and QShader has
  existing geometry shader support.

- OpenGL 3.2 and OpenGL ES 3.2 are working.

- D3D11 is not working.  D3D11 supports geometry shaders, but SPIRV-
  Cross does not support translating geometry shaders to HLSL.

- Metal is not working.  Metal does not directly support geometry
  shaders.

Change-Id: Ieb7c44c58b8be5f2e2197bf5133cf6847e6c132d
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Ben Fletcher 2022-01-27 12:27:27 -08:00
parent 1c3ae79ad3
commit 9ef702a37b
19 changed files with 276 additions and 7 deletions

View File

@ -711,6 +711,15 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
the way hull shaders are structured, whereas Metal uses a somewhat the way hull shaders are structured, whereas Metal uses a somewhat
different tessellation pipeline than others), and therefore no guarantees different tessellation pipeline than others), and therefore no guarantees
can be given for a universal solution for now. can be given for a universal solution for now.
\value GeometryShader Indicates that the geometry shader stage is
supported. When supported, a geometry shader can be specified in the
QRhiShaderStage list. \b{Geometry Shaders are considered an experimental
feature in QRhi and can only be expected to be supported with Vulkan,
OpenGL (3.2+) and OpenGL ES (3.2+) for the time being}, assuming the
implementation reports it as supported at run time. Geometry shaders have
portability issues between APIs, and therefore no guarantees can be given
for a universal solution for now.
*/ */
/*! /*!
@ -1470,6 +1479,9 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
\value Compute Compute stage. Must be used only when the QRhi::Compute \value Compute Compute stage. Must be used only when the QRhi::Compute
feature is supported. feature is supported.
\value Geometry Geometry stage. Must be used only when the
QRhi::GeometryShader feature is supported.
*/ */
/*! /*!
@ -3269,6 +3281,7 @@ void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
\value TessellationEvaluationStage Tessellation evaluation (domain shader) stage \value TessellationEvaluationStage Tessellation evaluation (domain shader) stage
\value FragmentStage Fragment (pixel shader) stage \value FragmentStage Fragment (pixel shader) stage
\value ComputeStage Compute stage \value ComputeStage Compute stage
\value GeometryStage Geometry stage
*/ */
/*! /*!
@ -7454,6 +7467,8 @@ QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBuffe
return QRhiPassResourceTracker::BufFragmentStage; return QRhiPassResourceTracker::BufFragmentStage;
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage)) if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
return QRhiPassResourceTracker::BufComputeStage; return QRhiPassResourceTracker::BufComputeStage;
if (stages.testFlag(QRhiShaderResourceBinding::GeometryStage))
return QRhiPassResourceTracker::BufGeometryStage;
Q_UNREACHABLE(); Q_UNREACHABLE();
return QRhiPassResourceTracker::BufVertexStage; return QRhiPassResourceTracker::BufVertexStage;
@ -7472,6 +7487,8 @@ QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerText
return QRhiPassResourceTracker::TexFragmentStage; return QRhiPassResourceTracker::TexFragmentStage;
if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage)) if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
return QRhiPassResourceTracker::TexComputeStage; return QRhiPassResourceTracker::TexComputeStage;
if (stages.testFlag(QRhiShaderResourceBinding::GeometryStage))
return QRhiPassResourceTracker::TexGeometryStage;
Q_UNREACHABLE(); Q_UNREACHABLE();
return QRhiPassResourceTracker::TexVertexStage; return QRhiPassResourceTracker::TexVertexStage;

View File

@ -297,6 +297,7 @@ public:
Vertex, Vertex,
TessellationControl, TessellationControl,
TessellationEvaluation, TessellationEvaluation,
Geometry,
Fragment, Fragment,
Compute Compute
}; };
@ -351,8 +352,9 @@ public:
VertexStage = 1 << 0, VertexStage = 1 << 0,
TessellationControlStage = 1 << 1, TessellationControlStage = 1 << 1,
TessellationEvaluationStage = 1 << 2, TessellationEvaluationStage = 1 << 2,
FragmentStage = 1 << 3, GeometryStage = 1 << 3,
ComputeStage = 1 << 4 FragmentStage = 1 << 4,
ComputeStage = 1 << 5
}; };
Q_DECLARE_FLAGS(StageFlags, StageFlag) Q_DECLARE_FLAGS(StageFlags, StageFlag)
@ -1673,7 +1675,8 @@ public:
ThreeDimensionalTextures, ThreeDimensionalTextures,
RenderTo3DTextureSlice, RenderTo3DTextureSlice,
TextureArrays, TextureArrays,
Tessellation Tessellation,
GeometryShader
}; };
enum BeginFrameFlag { enum BeginFrameFlag {

View File

@ -613,7 +613,8 @@ public:
BufTCStage, BufTCStage,
BufTEStage, BufTEStage,
BufFragmentStage, BufFragmentStage,
BufComputeStage BufComputeStage,
BufGeometryStage
}; };
enum BufferAccess { enum BufferAccess {
@ -635,7 +636,8 @@ public:
TexFragmentStage, TexFragmentStage,
TexColorOutputStage, TexColorOutputStage,
TexDepthOutputStage, TexDepthOutputStage,
TexComputeStage TexComputeStage,
TexGeometryStage
}; };
enum TextureAccess { enum TextureAccess {

View File

@ -565,6 +565,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true; return true;
case QRhi::Tessellation: case QRhi::Tessellation:
return false; return false;
case QRhi::GeometryShader:
return false;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return false; return false;

View File

@ -466,6 +466,10 @@ QT_BEGIN_NAMESPACE
#define GL_PATCHES 0x000E #define GL_PATCHES 0x000E
#endif #endif
#ifndef GL_GEOMETRY_SHADER
#define GL_GEOMETRY_SHADER 0x8DD9
#endif
/*! /*!
Constructs a new QRhiGles2InitParams. Constructs a new QRhiGles2InitParams.
@ -867,6 +871,11 @@ bool QRhiGles2::create(QRhi::Flags flags)
else else
caps.tessellation = caps.ctxMajor >= 4; // 4.0 caps.tessellation = caps.ctxMajor >= 4; // 4.0
if (caps.gles)
caps.geometryShader = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // ES 3.2
else
caps.geometryShader = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // 3.2
if (caps.ctxMajor >= 3) { // 3.0 or ES 3.0 if (caps.ctxMajor >= 3) { // 3.0 or ES 3.0
GLint maxArraySize = 0; GLint maxArraySize = 0;
f->glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArraySize); f->glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArraySize);
@ -1266,6 +1275,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return caps.maxTextureArraySize > 0; return caps.maxTextureArraySize > 0;
case QRhi::Tessellation: case QRhi::Tessellation:
return caps.tessellation; return caps.tessellation;
case QRhi::GeometryShader:
return caps.geometryShader;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return false; return false;
@ -4238,6 +4249,8 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
return GL_TESS_CONTROL_SHADER; return GL_TESS_CONTROL_SHADER;
case QRhiShaderStage::TessellationEvaluation: case QRhiShaderStage::TessellationEvaluation:
return GL_TESS_EVALUATION_SHADER; return GL_TESS_EVALUATION_SHADER;
case QRhiShaderStage::Geometry:
return GL_GEOMETRY_SHADER;
case QRhiShaderStage::Fragment: case QRhiShaderStage::Fragment:
return GL_FRAGMENT_SHADER; return GL_FRAGMENT_SHADER;
case QRhiShaderStage::Compute: case QRhiShaderStage::Compute:
@ -4519,6 +4532,8 @@ static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
return QShader::TessellationControlStage; return QShader::TessellationControlStage;
case QRhiShaderStage::TessellationEvaluation: case QRhiShaderStage::TessellationEvaluation:
return QShader::TessellationEvaluationStage; return QShader::TessellationEvaluationStage;
case QRhiShaderStage::Geometry:
return QShader::GeometryStage;
case QRhiShaderStage::Fragment: case QRhiShaderStage::Fragment:
return QShader::FragmentStage; return QShader::FragmentStage;
case QRhiShaderStage::Compute: case QRhiShaderStage::Compute:
@ -5447,6 +5462,7 @@ static inline bool isGraphicsStage(const QRhiShaderStage &shaderStage)
return t == QRhiShaderStage::Vertex return t == QRhiShaderStage::Vertex
|| t == QRhiShaderStage::TessellationControl || t == QRhiShaderStage::TessellationControl
|| t == QRhiShaderStage::TessellationEvaluation || t == QRhiShaderStage::TessellationEvaluation
|| t == QRhiShaderStage::Geometry
|| t == QRhiShaderStage::Fragment; || t == QRhiShaderStage::Fragment;
} }
@ -5469,8 +5485,9 @@ bool QGles2GraphicsPipeline::create()
enum { enum {
VtxIdx = 0, VtxIdx = 0,
TEIdx,
TCIdx, TCIdx,
TEIdx,
GeomIdx,
FragIdx, FragIdx,
LastIdx LastIdx
}; };
@ -5482,6 +5499,8 @@ bool QGles2GraphicsPipeline::create()
return TCIdx; return TCIdx;
case QRhiShaderStage::TessellationEvaluation: case QRhiShaderStage::TessellationEvaluation:
return TEIdx; return TEIdx;
case QRhiShaderStage::Geometry:
return GeomIdx;
case QRhiShaderStage::Fragment: case QRhiShaderStage::Fragment:
return FragIdx; return FragIdx;
default: default:

View File

@ -968,7 +968,8 @@ public:
screenSpaceDerivatives(false), screenSpaceDerivatives(false),
programBinary(false), programBinary(false),
texture3D(false), texture3D(false),
tessellation(false) tessellation(false),
geometryShader(false)
{ } { }
int ctxMajor; int ctxMajor;
int ctxMinor; int ctxMinor;
@ -1018,6 +1019,7 @@ public:
uint programBinary : 1; uint programBinary : 1;
uint texture3D : 1; uint texture3D : 1;
uint tessellation : 1; uint tessellation : 1;
uint geometryShader : 1;
} caps; } caps;
QGles2SwapChain *currentSwapChain = nullptr; QGles2SwapChain *currentSwapChain = nullptr;
QSet<GLint> supportedCompressedFormats; QSet<GLint> supportedCompressedFormats;

View File

@ -620,6 +620,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return true; return true;
case QRhi::Tessellation: case QRhi::Tessellation:
return false; return false;
case QRhi::GeometryShader:
return false;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return false; return false;

View File

@ -633,6 +633,8 @@ bool QRhiVulkan::create(QRhi::Flags flags)
features.textureCompressionASTC_LDR = VK_TRUE; features.textureCompressionASTC_LDR = VK_TRUE;
if (physDevFeatures.textureCompressionBC) if (physDevFeatures.textureCompressionBC)
features.textureCompressionBC = VK_TRUE; features.textureCompressionBC = VK_TRUE;
if (physDevFeatures.geometryShader)
features.geometryShader = VK_TRUE;
devInfo.pEnabledFeatures = &features; devInfo.pEnabledFeatures = &features;
VkResult err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev); VkResult err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
@ -696,6 +698,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
caps.texture3DSliceAs2D = caps.vulkan11OrHigher; caps.texture3DSliceAs2D = caps.vulkan11OrHigher;
caps.tessellation = physDevFeatures.tessellationShader; caps.tessellation = physDevFeatures.tessellationShader;
caps.geometryShader = physDevFeatures.geometryShader;
if (!importedAllocator) { if (!importedAllocator) {
VmaVulkanFunctions afuncs; VmaVulkanFunctions afuncs;
@ -3987,6 +3990,8 @@ static inline VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::Bu
return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
case QRhiPassResourceTracker::BufComputeStage: case QRhiPassResourceTracker::BufComputeStage:
return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
case QRhiPassResourceTracker::BufGeometryStage:
return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
break; break;
@ -4061,6 +4066,8 @@ static inline VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::Te
return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
case QRhiPassResourceTracker::TexComputeStage: case QRhiPassResourceTracker::TexComputeStage:
return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
case QRhiPassResourceTracker::TexGeometryStage:
return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
break; break;
@ -4317,6 +4324,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return true; return true;
case QRhi::Tessellation: case QRhi::Tessellation:
return caps.tessellation; return caps.tessellation;
case QRhi::GeometryShader:
return caps.geometryShader;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return false; return false;
@ -5267,6 +5276,8 @@ static inline VkShaderStageFlagBits toVkShaderStage(QRhiShaderStage::Type type)
return VK_SHADER_STAGE_FRAGMENT_BIT; return VK_SHADER_STAGE_FRAGMENT_BIT;
case QRhiShaderStage::Compute: case QRhiShaderStage::Compute:
return VK_SHADER_STAGE_COMPUTE_BIT; return VK_SHADER_STAGE_COMPUTE_BIT;
case QRhiShaderStage::Geometry:
return VK_SHADER_STAGE_GEOMETRY_BIT;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return VK_SHADER_STAGE_VERTEX_BIT; return VK_SHADER_STAGE_VERTEX_BIT;
@ -5559,6 +5570,8 @@ static inline VkShaderStageFlags toVkShaderStageFlags(QRhiShaderResourceBinding:
s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; s |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) if (stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage))
s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; s |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
if (stage.testFlag(QRhiShaderResourceBinding::GeometryStage))
s |= VK_SHADER_STAGE_GEOMETRY_BIT;
return VkShaderStageFlags(s); return VkShaderStageFlags(s);
} }

View File

@ -891,6 +891,7 @@ public:
bool texture3DSliceAs2D = false; bool texture3DSliceAs2D = false;
bool tessellation = false; bool tessellation = false;
bool vulkan11OrHigher = false; bool vulkan11OrHigher = false;
bool geometryShader = false;
} caps; } caps;
VkPipelineCache pipelineCache = VK_NULL_HANDLE; VkPipelineCache pipelineCache = VK_NULL_HANDLE;

View File

@ -25,3 +25,4 @@ add_subdirectory(tex3d)
add_subdirectory(texturearray) add_subdirectory(texturearray)
add_subdirectory(polygonmode) add_subdirectory(polygonmode)
add_subdirectory(tessellation) add_subdirectory(tessellation)
add_subdirectory(geometryshader)

View File

@ -0,0 +1,21 @@
qt_internal_add_manual_test(geometryshader
GUI
SOURCES
geometryshader.cpp
PUBLIC_LIBRARIES
Qt::Gui
Qt::GuiPrivate
)
set(geometryshader_resource_files
"test.vert.qsb"
"test.geom.qsb"
"test.frag.qsb"
)
qt_internal_add_resource(geometryshader "geometryshader"
PREFIX
"/"
FILES
${geometryshader_resource_files}
)

View File

@ -0,0 +1,3 @@
qsb --glsl 320es,410 test.vert -o test.vert.qsb
qsb --glsl 320es,410 test.geom -o test.geom.qsb
qsb --glsl 320es,410 test.frag -o test.frag.qsb

View File

@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../shared/examplefw.h"
static const float points[] = { 0.0f, 0.0f, 0.0f };
struct
{
QVector<QRhiResource *> releasePool;
QRhiBuffer *vbuf = nullptr;
QRhiBuffer *ubuf = nullptr;
QRhiShaderResourceBindings *srb = nullptr;
QRhiGraphicsPipeline *ps = nullptr;
QRhiResourceUpdateBatch *initialUpdates = nullptr;
float radius = 0.0f;
} d;
void Window::customInit()
{
if (!m_r->isFeatureSupported(QRhi::GeometryShader))
qFatal("Geometry shaders are not supported");
m_clearColor.setRgb(0, 0, 0);
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(points));
d.vbuf->create();
d.releasePool << d.vbuf;
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 4);
d.ubuf->create();
d.releasePool << d.ubuf;
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
const QRhiShaderResourceBinding::StageFlags geom = QRhiShaderResourceBinding::GeometryStage;
d.srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, geom, d.ubuf) });
d.srb->create();
d.ps = m_r->newGraphicsPipeline();
d.releasePool << d.ps;
d.ps->setTopology(QRhiGraphicsPipeline::Points);
d.ps->setShaderStages(
{ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/test.vert.qsb")) },
{ QRhiShaderStage::Geometry, getShader(QLatin1String(":/test.geom.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/test.frag.qsb")) } });
d.ps->setCullMode(QRhiGraphicsPipeline::Back);
d.ps->setDepthTest(true);
d.ps->setDepthWrite(true);
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({ { 3 * sizeof(float) } });
inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
d.ps->setVertexInputLayout(inputLayout);
d.ps->setShaderResourceBindings(d.srb);
d.ps->setRenderPassDescriptor(m_rp);
d.ps->create();
d.initialUpdates = m_r->nextResourceUpdateBatch();
d.initialUpdates->uploadStaticBuffer(d.vbuf, points);
d.initialUpdates->updateDynamicBuffer(d.ubuf, 0, 4, &d.radius);
}
void Window::customRelease()
{
qDeleteAll(d.releasePool);
d.releasePool.clear();
}
void Window::customRender()
{
const QSize outputSizeInPixels = m_sc->currentPixelSize();
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
if (d.initialUpdates) {
u->merge(d.initialUpdates);
d.initialUpdates->release();
d.initialUpdates = nullptr;
}
u->updateDynamicBuffer(d.ubuf, 0, 4, &d.radius);
d.radius = std::fmod(d.radius + 0.01f, 1.0f);
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u);
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(1);
cb->endPass();
}

View File

@ -0,0 +1,8 @@
#version 440
layout(location = 0) out vec4 fragColor;
void main()
{
fragColor = vec4(1.0);
}

Binary file not shown.

View File

@ -0,0 +1,26 @@
#version 430
# define M_PI 3.14159265358979323846
layout(points) in;
layout(line_strip, max_vertices = 7) out;
layout(std140, binding = 0) uniform buf {
float radius;
};
void main(void)
{
for(int i=0;i<7;++i)
{
float theta = float(i) / 6.0f * 2.0 * M_PI;
gl_Position = gl_in[0].gl_Position;
gl_Position.xy += radius * vec2(cos(theta), sin(theta));
EmitVertex();
}
EndPrimitive();
}

Binary file not shown.

View File

@ -0,0 +1,8 @@
#version 440
layout(location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}

Binary file not shown.