diff options
Diffstat (limited to 'tests/manual/rhi/tex3d')
-rw-r--r-- | tests/manual/rhi/tex3d/CMakeLists.txt | 23 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/buildshaders.bat | 2 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/tex3d.cpp | 227 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/tex3d.pro | 8 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/tex3d.qrc | 6 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/texture3d.frag | 24 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/texture3d.frag.qsb | bin | 0 -> 1729 bytes | |||
-rw-r--r-- | tests/manual/rhi/tex3d/texture3d.vert | 22 | ||||
-rw-r--r-- | tests/manual/rhi/tex3d/texture3d.vert.qsb | bin | 0 -> 1541 bytes |
9 files changed, 312 insertions, 0 deletions
diff --git a/tests/manual/rhi/tex3d/CMakeLists.txt b/tests/manual/rhi/tex3d/CMakeLists.txt new file mode 100644 index 0000000000..8b2ac292cf --- /dev/null +++ b/tests/manual/rhi/tex3d/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_manual_test(tex3d + GUI + SOURCES + tex3d.cpp + LIBRARIES + Qt::Gui + Qt::GuiPrivate +) + +set(tex3d_resource_files + "texture3d.vert.qsb" + "texture3d.frag.qsb" +) + +qt_internal_add_resource(tex3d "tex3d" + PREFIX + "/" + FILES + ${tex3d_resource_files} +) diff --git a/tests/manual/rhi/tex3d/buildshaders.bat b/tests/manual/rhi/tex3d/buildshaders.bat new file mode 100644 index 0000000000..041c554688 --- /dev/null +++ b/tests/manual/rhi/tex3d/buildshaders.bat @@ -0,0 +1,2 @@ +qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture3d.vert -o texture3d.vert.qsb +qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture3d.frag -o texture3d.frag.qsb diff --git a/tests/manual/rhi/tex3d/tex3d.cpp b/tests/manual/rhi/tex3d/tex3d.cpp new file mode 100644 index 0000000000..33c4cab8d1 --- /dev/null +++ b/tests/manual/rhi/tex3d/tex3d.cpp @@ -0,0 +1,227 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "../shared/examplefw.h" +#include <QImage> +#include <QPainter> + +// Create a 3D texture of 256x256x3, where we will render to one of the slices +// in a render pass, while providing data to two other slices in texture +// uploads. Finally we use the texture to in the on-screen rendering: texture 3 +// quads with the same volume texture, in each draw the shader will sample with +// a w that selects slice 0, 1, or 2, respectively. + +const int TEXTURE_DEPTH = 3; + +// Tests mipmap generation and linear-mipmap filtering when true. Note: Be +// aware what a mipmap chain for a 3D texture is and isn't, do not confuse with +// 2D (array) textures. The expected result on-screen is the black-red (slice +// 1) content mixed in to slice 0 and 2 on lower mip levels (resize the window +// to a smaller size -> the effect becomes more apparent, with totally taking +// over at small sizes) +// See https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-textures-intro +// +const bool MIPMAP = true; + +static float quadVertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 quadIndexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +struct { + QList<QRhiResource *> releasePool; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QRhiTexture *tex = nullptr; + QRhiTextureRenderTarget *rt = nullptr; + QRhiRenderPassDescriptor *rtRp = nullptr; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiSampler *sampler = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QMatrix4x4 winProj; + QVector3D slice1ClearColor; +} d; + +void Window::customInit() +{ + if (!m_r->isFeatureSupported(QRhi::ThreeDimensionalTextures)) + qWarning("3D textures are not supported"); + + QRhiTexture::Flags texFlags = QRhiTexture::RenderTarget; + if (MIPMAP) + texFlags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips; + d.tex = m_r->newTexture(QRhiTexture::RGBA8, + 256, 256, TEXTURE_DEPTH, + 1, texFlags); + d.releasePool << d.tex; + d.tex->create(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + + QImage imgWhiteText(256, 256, QImage::Format_RGBA8888); + imgWhiteText.fill(Qt::blue); + QPainter p(&imgWhiteText); + p.setPen(Qt::white); + p.drawText(10, 10, "Slice 2:\nWhite text on blue background"); + p.end(); + + // imgWhiteText -> slice 2 of the 3D texture + QRhiTextureUploadEntry uploadSlice2(2, 0, QRhiTextureSubresourceUploadDescription(imgWhiteText)); + d.initialUpdates->uploadTexture(d.tex, uploadSlice2); + + QImage imgYellowText(256, 256, QImage::Format_RGBA8888); + imgYellowText.fill(Qt::green); + p.begin(&imgYellowText); + p.setPen(Qt::yellow); + p.drawText(10, 10, "Slice 0: Yellow text on green background"); + p.end(); + + // imgYellowText -> slice 0 of the 3D texture + QRhiTextureUploadEntry uploadSlice0(0, 0, QRhiTextureSubresourceUploadDescription(imgYellowText)); + d.initialUpdates->uploadTexture(d.tex, uploadSlice0); + + // slice 1 -> clear to some color in a render pass + QRhiColorAttachment att(d.tex); + att.setLayer(1); + QRhiTextureRenderTargetDescription rtDesc(att); + d.rt = m_r->newTextureRenderTarget(rtDesc); + d.releasePool << d.rt; + d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.rtRp; + d.rt->setRenderPassDescriptor(d.rtRp); + d.rt->create(); + + // set up resources needed to render a quad + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData)); + d.vbuf->create(); + d.releasePool << d.vbuf; + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData)); + d.ibuf->create(); + d.releasePool << d.ibuf; + + d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(quadVertexData), quadVertexData); + d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData); + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, m_r->ubufAligned(72) * TEXTURE_DEPTH); + d.ubuf->create(); + d.releasePool << d.ubuf; + + for (int i = 0; i < TEXTURE_DEPTH; ++i) { + qint32 flip = 0; + if (i == 1) // this slice will be rendered to in a render pass so needs flipping with OpenGL when on screen + flip = m_r->isYUpInFramebuffer() ? 1 : 0; + d.initialUpdates->updateDynamicBuffer(d.ubuf, m_r->ubufAligned(72) * i + 64, 4, &flip); + qint32 idx = i; + d.initialUpdates->updateDynamicBuffer(d.ubuf, m_r->ubufAligned(72) * i + 68, 4, &idx); + } + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, MIPMAP ? QRhiSampler::Linear : QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->create(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 72), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->create(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture3d.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture3d.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 4 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, quint32(2 * sizeof(float)) } + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->create(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + if (d.winProj != m_proj) { + d.winProj = m_proj; + for (int i = 0; i < TEXTURE_DEPTH; ++i) { + QMatrix4x4 mvp = m_proj; + switch (i) { + case 0: + mvp.translate(-2.0f, 0.0f, 0.0f); + break; + case 2: + mvp.translate(2.0f, 0.0f, 0.0f); + break; + default: + break; + } + u->updateDynamicBuffer(d.ubuf, m_r->ubufAligned(72) * i, 64, mvp.constData()); + } + } + + const QColor slice1ClearColor = QColor::fromRgbF(d.slice1ClearColor.x(), d.slice1ClearColor.y(), d.slice1ClearColor.z()); + d.slice1ClearColor.setX(d.slice1ClearColor.x() + 0.01f); + if (d.slice1ClearColor.x() > 1.0f) + d.slice1ClearColor.setX(0.0f); + cb->beginPass(d.rt, slice1ClearColor, { 1.0f, 0 }, u); + cb->endPass(); + + // now all 3 slices have something, regenerate the mipmaps + u = m_r->nextResourceUpdateBatch(); + if (MIPMAP) + u->generateMips(d.tex); + + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + QRhiCommandBuffer::DynamicOffset dynOfs = { 0, 0 }; + cb->setShaderResources(d.srb, 1, &dynOfs); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + + dynOfs.second = m_r->ubufAligned(72); + cb->setShaderResources(d.srb, 1, &dynOfs); + cb->drawIndexed(6); + + dynOfs.second = m_r->ubufAligned(72) * 2; + cb->setShaderResources(d.srb, 1, &dynOfs); + cb->drawIndexed(6); + + cb->endPass(); +} diff --git a/tests/manual/rhi/tex3d/tex3d.pro b/tests/manual/rhi/tex3d/tex3d.pro new file mode 100644 index 0000000000..97a1c90372 --- /dev/null +++ b/tests/manual/rhi/tex3d/tex3d.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + tex3d.cpp + +RESOURCES = tex3d.qrc diff --git a/tests/manual/rhi/tex3d/tex3d.qrc b/tests/manual/rhi/tex3d/tex3d.qrc new file mode 100644 index 0000000000..f1c722382a --- /dev/null +++ b/tests/manual/rhi/tex3d/tex3d.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>texture3d.vert.qsb</file> + <file>texture3d.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/tex3d/texture3d.frag b/tests/manual/rhi/tex3d/texture3d.frag new file mode 100644 index 0000000000..2b3eb8895d --- /dev/null +++ b/tests/manual/rhi/tex3d/texture3d.frag @@ -0,0 +1,24 @@ +#version 440 + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + int flip; + int idx; +} ubuf; + +layout(binding = 1) uniform sampler3D tex; + +void main() +{ + float w = 0.0; + if (ubuf.idx == 1) + w = 0.5; + else if (ubuf.idx == 2) + w = 1.0; + vec4 c = texture(tex, vec3(v_texcoord, w)); + fragColor = vec4(c.rgb * c.a, c.a); +} diff --git a/tests/manual/rhi/tex3d/texture3d.frag.qsb b/tests/manual/rhi/tex3d/texture3d.frag.qsb Binary files differnew file mode 100644 index 0000000000..33224b2385 --- /dev/null +++ b/tests/manual/rhi/tex3d/texture3d.frag.qsb diff --git a/tests/manual/rhi/tex3d/texture3d.vert b/tests/manual/rhi/tex3d/texture3d.vert new file mode 100644 index 0000000000..2b46dc84aa --- /dev/null +++ b/tests/manual/rhi/tex3d/texture3d.vert @@ -0,0 +1,22 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 v_texcoord; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + int flip; + int idx; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_texcoord = vec2(texcoord.x, texcoord.y); + if (ubuf.flip != 0) + v_texcoord.y = 1.0 - v_texcoord.y; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/tex3d/texture3d.vert.qsb b/tests/manual/rhi/tex3d/texture3d.vert.qsb Binary files differnew file mode 100644 index 0000000000..daf6d0407a --- /dev/null +++ b/tests/manual/rhi/tex3d/texture3d.vert.qsb |