mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-04 00:05:25 +08:00
qt 6.6.0 clean
This commit is contained in:
@ -30,6 +30,8 @@ add_subdirectory(geometryshader)
|
||||
add_subdirectory(stenciloutline)
|
||||
add_subdirectory(stereo)
|
||||
add_subdirectory(tex1d)
|
||||
add_subdirectory(displacement)
|
||||
add_subdirectory(imguirenderer)
|
||||
if(QT_FEATURE_widgets)
|
||||
add_subdirectory(rhiwidget)
|
||||
endif()
|
||||
|
26
tests/manual/rhi/displacement/CMakeLists.txt
Normal file
26
tests/manual/rhi/displacement/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_manual_test(displacement
|
||||
GUI
|
||||
SOURCES
|
||||
displacement.cpp
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
qt_internal_add_resource(displacement "displacement"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
"material.vert.qsb"
|
||||
"material.tesc.qsb"
|
||||
"material.tese.qsb"
|
||||
"material.frag.qsb"
|
||||
"heightmap.png"
|
||||
)
|
||||
|
||||
set(imgui_base ../shared/imgui)
|
||||
set(imgui_target displacement)
|
||||
include(${imgui_base}/imgui.cmakeinc)
|
7
tests/manual/rhi/displacement/buildshaders
Normal file
7
tests/manual/rhi/displacement/buildshaders
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
qsb --glsl 320es,410 --hlsl 50 --msl 12 --msltess material.vert -o material.vert.qsb
|
||||
qsb --glsl 320es,410 --hlsl 50 --msl 12 material.frag -o material.frag.qsb
|
||||
qsb --glsl 320es,410 --msl 12 --tess-mode triangles material.tesc -o material.tesc.qsb
|
||||
qsb --glsl 320es,410 --msl 12 --tess-vertex-count 3 material.tese -o material.tese.qsb
|
||||
qsb -r hlsl,50,material_hull.hlsl material.tesc.qsb
|
||||
qsb -r hlsl,50,material_domain.hlsl material.tese.qsb
|
8
tests/manual/rhi/displacement/buildshaders.bat
Normal file
8
tests/manual/rhi/displacement/buildshaders.bat
Normal file
@ -0,0 +1,8 @@
|
||||
qsb --glsl 320es,410 --hlsl 50 --msl 12 --msltess material.vert -o material.vert.qsb
|
||||
qsb --glsl 320es,410 --hlsl 50 --msl 12 material.frag -o material.frag.qsb
|
||||
|
||||
qsb --glsl 320es,410 --msl 12 --tess-mode triangles material.tesc -o material.tesc.qsb
|
||||
qsb --glsl 320es,410 --msl 12 --tess-vertex-count 3 material.tese -o material.tese.qsb
|
||||
|
||||
qsb -r hlsl,50,material_hull.hlsl material.tesc.qsb
|
||||
qsb -r hlsl,50,material_domain.hlsl material.tese.qsb
|
199
tests/manual/rhi/displacement/displacement.cpp
Normal file
199
tests/manual/rhi/displacement/displacement.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#define EXAMPLEFW_IMGUI
|
||||
#include "../shared/examplefw.h"
|
||||
#include "../shared/cube.h"
|
||||
|
||||
// Another tessellation test. Compatible with Direct 3D via hand-written hull
|
||||
// and domain shaders, but this already pushes the limits of what is sensible
|
||||
// when it comes to injecting hand-written HLSL code to get tessellation
|
||||
// functional (cbuffer layout, resource registers all need to be figured out
|
||||
// manually and works only as long as the GLSL source is not changing, etc.).
|
||||
// Note that the domain shader must use SampleLevel (textureLod), it won't
|
||||
// compile for ds_5_0 otherwise.
|
||||
|
||||
static const quint32 UBUF_SIZE = 80;
|
||||
|
||||
struct {
|
||||
QList<QRhiResource *> releasePool;
|
||||
|
||||
QRhiBuffer *vbuf;
|
||||
QRhiBuffer *ubuf;
|
||||
QRhiTexture *tex;
|
||||
QRhiSampler *sampler;
|
||||
QRhiShaderResourceBindings *srb;
|
||||
QRhiGraphicsPipeline *psWire;
|
||||
QRhiGraphicsPipeline *psSolid;
|
||||
bool rotate = true;
|
||||
float rotation = 0.0f;
|
||||
float viewZ = 0.0f;
|
||||
float displacementAmount = 0.0f;
|
||||
int tessInner = 4;
|
||||
int tessOuter = 4;
|
||||
bool useTex = false;
|
||||
bool wireframe = true;
|
||||
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
} d;
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
if (!m_r->isFeatureSupported(QRhi::Tessellation))
|
||||
qFatal("Tessellation is not supported");
|
||||
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
|
||||
d.vbuf->create();
|
||||
d.releasePool << d.vbuf;
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.vbuf, cube);
|
||||
|
||||
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, m_r->ubufAligned(UBUF_SIZE));
|
||||
d.ubuf->create();
|
||||
d.releasePool << d.ubuf;
|
||||
|
||||
QImage image;
|
||||
image.load(":/heightmap.png");
|
||||
if (image.isNull())
|
||||
qFatal("Failed to load displacement map");
|
||||
|
||||
d.tex = m_r->newTexture(QRhiTexture::RGBA8, image.size());
|
||||
d.tex->create();
|
||||
d.releasePool << d.tex;
|
||||
|
||||
d.initialUpdates->uploadTexture(d.tex, image);
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
QRhiSampler::Repeat, QRhiSampler::Repeat);
|
||||
d.releasePool << d.sampler;
|
||||
d.sampler->create();
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0,
|
||||
QRhiShaderResourceBinding::TessellationControlStage
|
||||
| QRhiShaderResourceBinding::TessellationEvaluationStage,
|
||||
d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::TessellationEvaluationStage, d.tex, d.sampler)
|
||||
});
|
||||
d.srb->create();
|
||||
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 3 * sizeof(float) },
|
||||
{ 2 * sizeof(float) },
|
||||
{ 3 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float3, 0 },
|
||||
{ 1, 1, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 2, 2, QRhiVertexInputAttribute::Float3, 0 }
|
||||
});
|
||||
|
||||
const QRhiShaderStage stages[] = {
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/material.vert.qsb")) },
|
||||
{ QRhiShaderStage::TessellationControl, getShader(QLatin1String(":/material.tesc.qsb")) },
|
||||
{ QRhiShaderStage::TessellationEvaluation, getShader(QLatin1String(":/material.tese.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/material.frag.qsb")) }
|
||||
};
|
||||
|
||||
d.psWire = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.psWire;
|
||||
d.psWire->setTopology(QRhiGraphicsPipeline::Patches);
|
||||
d.psWire->setPatchControlPointCount(3);
|
||||
d.psWire->setShaderStages(stages, stages + 4);
|
||||
d.psWire->setDepthTest(true);
|
||||
d.psWire->setDepthWrite(true);
|
||||
d.psWire->setCullMode(QRhiGraphicsPipeline::Back);
|
||||
d.psWire->setPolygonMode(QRhiGraphicsPipeline::Line);
|
||||
d.psWire->setVertexInputLayout(inputLayout);
|
||||
d.psWire->setShaderResourceBindings(d.srb);
|
||||
d.psWire->setRenderPassDescriptor(m_rp);
|
||||
d.psWire->create();
|
||||
|
||||
d.psSolid = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.psSolid;
|
||||
d.psSolid->setTopology(QRhiGraphicsPipeline::Patches);
|
||||
d.psSolid->setPatchControlPointCount(3);
|
||||
d.psSolid->setShaderStages(stages, stages + 4);
|
||||
d.psSolid->setDepthTest(true);
|
||||
d.psSolid->setDepthWrite(true);
|
||||
d.psSolid->setCullMode(QRhiGraphicsPipeline::Back);
|
||||
d.psSolid->setVertexInputLayout(inputLayout);
|
||||
d.psSolid->setShaderResourceBindings(d.srb);
|
||||
d.psSolid->setRenderPassDescriptor(m_rp);
|
||||
d.psSolid->create();
|
||||
}
|
||||
|
||||
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 = nullptr;
|
||||
if (d.initialUpdates) {
|
||||
u = d.initialUpdates;
|
||||
d.initialUpdates = nullptr;
|
||||
}
|
||||
|
||||
char *p = d.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
|
||||
QMatrix4x4 mvp = m_proj;
|
||||
mvp.translate(0, 0, d.viewZ);
|
||||
mvp.rotate(d.rotation, 1, 1, 0);
|
||||
mvp.scale(0.5f);
|
||||
|
||||
memcpy(p, mvp.constData(), 64);
|
||||
memcpy(p + 64, &d.displacementAmount, sizeof(float));
|
||||
float tessInnerFloat = d.tessInner;
|
||||
memcpy(p + 68, &tessInnerFloat, sizeof(float));
|
||||
float tessOuterFloat = d.tessOuter;
|
||||
memcpy(p + 72, &tessOuterFloat, sizeof(float));
|
||||
qint32 useTex = d.useTex ? 1 : 0;
|
||||
memcpy(p + 76, &useTex, sizeof(qint32));
|
||||
|
||||
d.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
|
||||
|
||||
const QRhiCommandBuffer::VertexInput vbufBinding[] = {
|
||||
{ d.vbuf, 0 },
|
||||
{ d.vbuf, quint32(36 * 3 * sizeof(float)) },
|
||||
{ d.vbuf, quint32(36 * (3 + 2) * sizeof(float)) }
|
||||
};
|
||||
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u, QRhiCommandBuffer::DoNotTrackResourcesForCompute);
|
||||
|
||||
cb->setGraphicsPipeline(d.wireframe ? d.psWire : d.psSolid);
|
||||
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
|
||||
cb->setShaderResources(d.srb);
|
||||
cb->setVertexInput(0, 3, vbufBinding);
|
||||
cb->draw(36);
|
||||
|
||||
m_imguiRenderer->render();
|
||||
|
||||
cb->endPass();
|
||||
|
||||
if (d.rotate)
|
||||
d.rotation += 1;
|
||||
}
|
||||
|
||||
void Window::customGui()
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(500, 250), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Test");
|
||||
ImGui::SliderInt("Inner", &d.tessInner, 0, 20);
|
||||
ImGui::SliderInt("Outer", &d.tessOuter, 0, 20);
|
||||
ImGui::SliderFloat("Displacement", &d.displacementAmount, 0.0f, 4.0f);
|
||||
ImGui::Checkbox("Use displacement texture", &d.useTex);
|
||||
ImGui::SliderFloat("Z", &d.viewZ, -16.0f, 4.0f);
|
||||
ImGui::Checkbox("Rotate", &d.rotate);
|
||||
ImGui::Checkbox("Wireframe", &d.wireframe);
|
||||
ImGui::End();
|
||||
}
|
BIN
tests/manual/rhi/displacement/heightmap.png
Normal file
BIN
tests/manual/rhi/displacement/heightmap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 KiB |
10
tests/manual/rhi/displacement/material.frag
Normal file
10
tests/manual/rhi/displacement/material.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 1) in vec3 in_normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4((normalize(in_normal) + 1.0) / 2.0, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/displacement/material.frag.qsb
Normal file
BIN
tests/manual/rhi/displacement/material.frag.qsb
Normal file
Binary file not shown.
32
tests/manual/rhi/displacement/material.tesc
Normal file
32
tests/manual/rhi/displacement/material.tesc
Normal file
@ -0,0 +1,32 @@
|
||||
#version 440
|
||||
|
||||
layout(vertices = 3) out;
|
||||
|
||||
layout(location = 0) in vec2 in_uv[];
|
||||
layout(location = 1) in vec3 in_normal[];
|
||||
|
||||
layout(location = 0) out vec2 out_uv[];
|
||||
layout(location = 1) out vec3 out_normal[];
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float displacementAmount;
|
||||
float tessInner;
|
||||
float tessOuter;
|
||||
int useTex;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
if (gl_InvocationID == 0) {
|
||||
gl_TessLevelOuter[0] = tessOuter;
|
||||
gl_TessLevelOuter[1] = tessOuter;
|
||||
gl_TessLevelOuter[2] = tessOuter;
|
||||
|
||||
gl_TessLevelInner[0] = tessInner;
|
||||
}
|
||||
|
||||
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
||||
out_uv[gl_InvocationID] = in_uv[gl_InvocationID];
|
||||
out_normal[gl_InvocationID] = in_normal[gl_InvocationID];
|
||||
}
|
BIN
tests/manual/rhi/displacement/material.tesc.qsb
Normal file
BIN
tests/manual/rhi/displacement/material.tesc.qsb
Normal file
Binary file not shown.
37
tests/manual/rhi/displacement/material.tese
Normal file
37
tests/manual/rhi/displacement/material.tese
Normal file
@ -0,0 +1,37 @@
|
||||
#version 440
|
||||
|
||||
layout(triangles, fractional_odd_spacing, ccw) in;
|
||||
|
||||
layout(location = 0) in vec2 in_uv[];
|
||||
layout(location = 1) in vec3 in_normal[];
|
||||
|
||||
//layout(location = 0) out vec2 out_uv;
|
||||
layout(location = 1) out vec3 out_normal;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float displacementAmount;
|
||||
float tessInner;
|
||||
float tessOuter;
|
||||
int useTex;
|
||||
};
|
||||
|
||||
layout(binding = 1) uniform sampler2D displacementMap;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = (gl_TessCoord.x * gl_in[0].gl_Position) + (gl_TessCoord.y * gl_in[1].gl_Position) + (gl_TessCoord.z * gl_in[2].gl_Position);
|
||||
vec2 uv = gl_TessCoord.x * in_uv[0].xy + gl_TessCoord.y * in_uv[1].xy;
|
||||
vec3 normal = normalize(gl_TessCoord.x * in_normal[0] + gl_TessCoord.y * in_normal[1] + gl_TessCoord.z * in_normal[2]);
|
||||
|
||||
vec4 c = texture(displacementMap, uv);
|
||||
const vec3 yCoeff_709 = vec3(0.2126, 0.7152, 0.0722);
|
||||
float df = dot(c.rgb, yCoeff_709);
|
||||
if (useTex == 0)
|
||||
df = 1.0;
|
||||
vec3 displacedPos = pos.xyz + normal * df * displacementAmount;
|
||||
gl_Position = mvp * vec4(displacedPos, 1.0);
|
||||
|
||||
// out_uv = uv;
|
||||
out_normal = normal;
|
||||
}
|
BIN
tests/manual/rhi/displacement/material.tese.qsb
Normal file
BIN
tests/manual/rhi/displacement/material.tese.qsb
Normal file
Binary file not shown.
15
tests/manual/rhi/displacement/material.vert
Normal file
15
tests/manual/rhi/displacement/material.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec2 uv;
|
||||
layout(location = 2) in vec3 normal;
|
||||
|
||||
layout(location = 0) out vec2 out_uv;
|
||||
layout(location = 1) out vec3 out_normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(position, 1.0);
|
||||
out_uv = uv;
|
||||
out_normal = normal;
|
||||
}
|
BIN
tests/manual/rhi/displacement/material.vert.qsb
Normal file
BIN
tests/manual/rhi/displacement/material.vert.qsb
Normal file
Binary file not shown.
54
tests/manual/rhi/displacement/material_domain.hlsl
Normal file
54
tests/manual/rhi/displacement/material_domain.hlsl
Normal file
@ -0,0 +1,54 @@
|
||||
struct Input
|
||||
{
|
||||
float edges[3] : SV_TessFactor;
|
||||
float inside : SV_InsideTessFactor;
|
||||
};
|
||||
|
||||
struct PatchInput
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
//float2 uv : TEXCOORD0;
|
||||
float3 normal : TEXCOORD1;
|
||||
float4 position : SV_POSITION;
|
||||
};
|
||||
|
||||
cbuffer buf : register(b0)
|
||||
{
|
||||
row_major float4x4 mvp : packoffset(c0);
|
||||
float displacementAmount : packoffset(c4);
|
||||
float tessInner : packoffset(c4.y);
|
||||
float tessOuter : packoffset(c4.z);
|
||||
int useTex : packoffset(c4.w);
|
||||
};
|
||||
|
||||
Texture2D<float4> tex : register(t1);
|
||||
SamplerState texsampler : register(s1);
|
||||
|
||||
[domain("tri")]
|
||||
PixelInput main(Input input, float3 uvwCoord : SV_DomainLocation, const OutputPatch<PatchInput, 3> patch)
|
||||
{
|
||||
PixelInput output;
|
||||
|
||||
float3 pos = uvwCoord.x * patch[0].position + uvwCoord.y * patch[1].position + uvwCoord.z * patch[2].position;
|
||||
float2 uv = uvwCoord.x * patch[0].uv + uvwCoord.y * patch[1].uv;
|
||||
float3 normal = normalize(uvwCoord.x * patch[0].normal + uvwCoord.y * patch[1].normal + uvwCoord.z * patch[2].normal);
|
||||
|
||||
float4 c = tex.SampleLevel(texsampler, uv, 0.0);
|
||||
const float3 yCoeff_709 = float3(0.2126, 0.7152, 0.0722);
|
||||
float df = dot(c.rgb, yCoeff_709);
|
||||
if (useTex == 0)
|
||||
df = 1.0;
|
||||
float3 displacedPos = pos + normal * df * displacementAmount;
|
||||
|
||||
output.position = mul(float4(displacedPos, 1.0), mvp);
|
||||
//output.uv = uv;
|
||||
output.normal = normal;
|
||||
|
||||
return output;
|
||||
}
|
52
tests/manual/rhi/displacement/material_hull.hlsl
Normal file
52
tests/manual/rhi/displacement/material_hull.hlsl
Normal file
@ -0,0 +1,52 @@
|
||||
struct Input
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : TEXCOORD1;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
struct Output
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct ConstantData
|
||||
{
|
||||
float edges[3] : SV_TessFactor;
|
||||
float inside : SV_InsideTessFactor;
|
||||
};
|
||||
|
||||
cbuffer buf : register(b0)
|
||||
{
|
||||
row_major float4x4 mvp : packoffset(c0);
|
||||
float displacementAmount : packoffset(c4);
|
||||
float tessInner : packoffset(c4.y);
|
||||
float tessOuter : packoffset(c4.z);
|
||||
int useTex : packoffset(c4.w);
|
||||
};
|
||||
|
||||
ConstantData patchConstFunc(InputPatch<Input, 3> ip, uint PatchID : SV_PrimitiveID )
|
||||
{
|
||||
ConstantData d;
|
||||
d.edges[0] = tessOuter;
|
||||
d.edges[1] = tessOuter;
|
||||
d.edges[2] = tessOuter;
|
||||
d.inside = tessInner;
|
||||
return d;
|
||||
}
|
||||
|
||||
[domain("tri")]
|
||||
[partitioning("integer")]
|
||||
[outputtopology("triangle_cw")]
|
||||
[outputcontrolpoints(3)]
|
||||
[patchconstantfunc("patchConstFunc")]
|
||||
Output main(InputPatch<Input, 3> patch, uint pointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)
|
||||
{
|
||||
Output output;
|
||||
output.position = patch[pointId].position;
|
||||
output.uv = patch[pointId].uv;
|
||||
output.normal = patch[pointId].normal;
|
||||
return output;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "hellowindow.h"
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
|
||||
static float vertexData[] = {
|
||||
// Y up (note clipSpaceCorrMatrix in m_proj), CCW
|
||||
|
@ -20,6 +20,8 @@ QString graphicsApiName(QRhi::Implementation graphicsApi)
|
||||
return QLatin1String("Vulkan");
|
||||
case QRhi::D3D11:
|
||||
return QLatin1String("Direct3D 11");
|
||||
case QRhi::D3D12:
|
||||
return QLatin1String("Direct3D 12");
|
||||
case QRhi::Metal:
|
||||
return QLatin1String("Metal");
|
||||
default:
|
||||
@ -51,8 +53,10 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(glOption);
|
||||
QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
|
||||
cmdLineParser.addOption(vkOption);
|
||||
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3dOption);
|
||||
QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3d11Option);
|
||||
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
|
||||
cmdLineParser.addOption(d3d12Option);
|
||||
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
|
||||
cmdLineParser.addOption(mtlOption);
|
||||
|
||||
@ -63,8 +67,10 @@ int main(int argc, char **argv)
|
||||
graphicsApi = QRhi::OpenGLES2;
|
||||
if (cmdLineParser.isSet(vkOption))
|
||||
graphicsApi = QRhi::Vulkan;
|
||||
if (cmdLineParser.isSet(d3dOption))
|
||||
if (cmdLineParser.isSet(d3d11Option))
|
||||
graphicsApi = QRhi::D3D11;
|
||||
if (cmdLineParser.isSet(d3d12Option))
|
||||
graphicsApi = QRhi::D3D12;
|
||||
if (cmdLineParser.isSet(mtlOption))
|
||||
graphicsApi = QRhi::Metal;
|
||||
|
||||
|
@ -16,6 +16,7 @@ Window::Window(QRhi::Implementation graphicsApi)
|
||||
setSurfaceType(VulkanSurface);
|
||||
break;
|
||||
case QRhi::D3D11:
|
||||
case QRhi::D3D12:
|
||||
setSurfaceType(Direct3DSurface);
|
||||
break;
|
||||
case QRhi::Metal:
|
||||
@ -81,7 +82,7 @@ bool Window::event(QEvent *e)
|
||||
|
||||
void Window::init()
|
||||
{
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers | QRhi::EnableProfiling;
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
||||
|
||||
if (m_graphicsApi == QRhi::Null) {
|
||||
QRhiNullInitParams params;
|
||||
@ -112,6 +113,10 @@ void Window::init()
|
||||
QRhiD3D11InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
m_rhi.reset(QRhi::create(QRhi::D3D11, ¶ms, rhiFlags));
|
||||
} else if (m_graphicsApi == QRhi::D3D12) {
|
||||
QRhiD3D12InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
m_rhi.reset(QRhi::create(QRhi::D3D12, ¶ms, rhiFlags));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -5,21 +5,8 @@
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWindow>
|
||||
|
||||
#include <QtGui/private/qrhinull_p.h>
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtGui/private/qrhid3d11_p.h>
|
||||
#endif
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#endif
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class Window : public QWindow
|
||||
{
|
||||
|
30
tests/manual/rhi/imguirenderer/CMakeLists.txt
Normal file
30
tests/manual/rhi/imguirenderer/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
qt_internal_add_manual_test(imguirenderer
|
||||
GUI
|
||||
SOURCES
|
||||
imguirenderer.cpp
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
set_source_files_properties("../shared/texture.vert.qsb"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "texture.vert.qsb"
|
||||
)
|
||||
set_source_files_properties("../shared/texture.frag.qsb"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "texture.frag.qsb"
|
||||
)
|
||||
set_source_files_properties("../shared/qt256.png"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "qt256.png"
|
||||
)
|
||||
qt_internal_add_resource(imguirenderer "imguirenderer"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
"../shared/texture.vert.qsb"
|
||||
"../shared/texture.frag.qsb"
|
||||
"../shared/qt256.png"
|
||||
)
|
||||
|
||||
set(imgui_base ../shared/imgui)
|
||||
set(imgui_target imguirenderer)
|
||||
include(${imgui_base}/imgui.cmakeinc)
|
128
tests/manual/rhi/imguirenderer/imguirenderer.cpp
Normal file
128
tests/manual/rhi/imguirenderer/imguirenderer.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#define EXAMPLEFW_IMGUI
|
||||
#include "../shared/examplefw.h"
|
||||
|
||||
#include "../shared/cube.h"
|
||||
|
||||
struct {
|
||||
QMatrix4x4 winProj;
|
||||
QList<QRhiResource *> releasePool;
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
QRhiBuffer *vbuf = nullptr;
|
||||
QRhiBuffer *ubuf = nullptr;
|
||||
QRhiTexture *tex = nullptr;
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
QRhiGraphicsPipeline *ps = nullptr;
|
||||
bool showDemoWindow = true;
|
||||
float rotation = 0.0f;
|
||||
} d;
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
|
||||
d.vbuf->create();
|
||||
d.releasePool << d.vbuf;
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.vbuf, cube);
|
||||
|
||||
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
|
||||
d.ubuf->create();
|
||||
d.releasePool << d.ubuf;
|
||||
float opacity = 1.0f;
|
||||
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &opacity);
|
||||
|
||||
QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888).mirrored();
|
||||
d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(image.width(), image.height()), 1, {});
|
||||
d.releasePool << d.tex;
|
||||
d.tex->create();
|
||||
d.initialUpdates->uploadTexture(d.tex, image);
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
|
||||
d.releasePool << d.sampler;
|
||||
d.sampler->create();
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
|
||||
});
|
||||
d.srb->create();
|
||||
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.ps;
|
||||
d.ps->setCullMode(QRhiGraphicsPipeline::Back);
|
||||
const QRhiShaderStage stages[] = {
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||
};
|
||||
d.ps->setShaderStages(stages, stages + 2);
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 3 * sizeof(float) },
|
||||
{ 2 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float3, 0 },
|
||||
{ 1, 1, QRhiVertexInputAttribute::Float2, 0 }
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
QMatrix4x4 mvp = m_proj;
|
||||
mvp.rotate(d.rotation, 0, 1, 0);
|
||||
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
|
||||
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u);
|
||||
|
||||
cb->setGraphicsPipeline(d.ps);
|
||||
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
|
||||
cb->setShaderResources();
|
||||
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
|
||||
{ d.vbuf, 0 },
|
||||
{ d.vbuf, quint32(36 * 3 * sizeof(float)) }
|
||||
};
|
||||
cb->setVertexInput(0, 2, vbufBindings);
|
||||
cb->draw(36);
|
||||
|
||||
m_imguiRenderer->render();
|
||||
|
||||
cb->endPass();
|
||||
}
|
||||
|
||||
void Window::customGui()
|
||||
{
|
||||
ImGui::ShowDemoWindow(&d.showDemoWindow);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(50, 120), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(400, 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Test");
|
||||
ImGui::SliderFloat("Rotation", &d.rotation, 0.0f, 360.0f);
|
||||
ImGui::End();
|
||||
}
|
@ -13,33 +13,17 @@
|
||||
#include <QWindow>
|
||||
#include <QPlatformSurfaceEvent>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <QFile>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QLoggingCategory>
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtGui/private/qrhid3d11_p.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#endif
|
||||
#include <QOffscreenSurface>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
enum GraphicsApi
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Metal
|
||||
};
|
||||
|
||||
@ -54,6 +38,8 @@ static QString graphicsApiName()
|
||||
return QLatin1String("Vulkan");
|
||||
case D3D11:
|
||||
return QLatin1String("Direct3D 11");
|
||||
case D3D12:
|
||||
return QLatin1String("Direct3D 12");
|
||||
case Metal:
|
||||
return QLatin1String("Metal");
|
||||
default:
|
||||
@ -98,6 +84,10 @@ void createRhi()
|
||||
QRhiD3D11InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r.r = QRhi::create(QRhi::D3D11, ¶ms);
|
||||
} else if (graphicsApi == D3D12) {
|
||||
QRhiD3D12InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r.r = QRhi::create(QRhi::D3D12, ¶ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -281,6 +271,7 @@ Window::Window(const QString &title, const QColor &bgColor, int axis, bool noVSy
|
||||
#endif
|
||||
break;
|
||||
case D3D11:
|
||||
case D3D12:
|
||||
setSurfaceType(Direct3DSurface);
|
||||
break;
|
||||
case Metal:
|
||||
@ -494,6 +485,8 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(vkOption);
|
||||
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3dOption);
|
||||
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
|
||||
cmdLineParser.addOption(d3d12Option);
|
||||
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
|
||||
cmdLineParser.addOption(mtlOption);
|
||||
cmdLineParser.process(app);
|
||||
@ -503,6 +496,8 @@ int main(int argc, char **argv)
|
||||
graphicsApi = Vulkan;
|
||||
if (cmdLineParser.isSet(d3dOption))
|
||||
graphicsApi = D3D11;
|
||||
if (cmdLineParser.isSet(d3d12Option))
|
||||
graphicsApi = D3D12;
|
||||
if (cmdLineParser.isSet(mtlOption))
|
||||
graphicsApi = Metal;
|
||||
|
||||
@ -517,6 +512,7 @@ int main(int argc, char **argv)
|
||||
r.instance = new QVulkanInstance;
|
||||
if (graphicsApi == Vulkan) {
|
||||
r.instance->setLayers({ "VK_LAYER_KHRONOS_validation" });
|
||||
r.instance->setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
|
||||
if (!r.instance->create()) {
|
||||
qWarning("Failed to create Vulkan instance, switching to OpenGL");
|
||||
graphicsApi = OpenGL;
|
||||
|
@ -16,27 +16,10 @@
|
||||
#include <QEvent>
|
||||
#include <QCommandLineParser>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <QFile>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QLoggingCategory>
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtGui/private/qrhid3d11_p.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#endif
|
||||
#include <QOffscreenSurface>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
@ -66,6 +49,8 @@ static QString graphicsApiName()
|
||||
return QLatin1String("Vulkan");
|
||||
case D3D11:
|
||||
return QLatin1String("Direct3D 11");
|
||||
case D3D12:
|
||||
return QLatin1String("Direct3D 12");
|
||||
case Metal:
|
||||
return QLatin1String("Metal");
|
||||
default:
|
||||
@ -329,6 +314,10 @@ void Renderer::createRhi()
|
||||
QRhiD3D11InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags);
|
||||
} else if (graphicsApi == D3D12) {
|
||||
QRhiD3D12InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r = QRhi::create(QRhi::D3D12, ¶ms, rhiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -681,6 +670,8 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(vkOption);
|
||||
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3dOption);
|
||||
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
|
||||
cmdLineParser.addOption(d3d12Option);
|
||||
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
|
||||
cmdLineParser.addOption(mtlOption);
|
||||
cmdLineParser.process(app);
|
||||
@ -690,6 +681,8 @@ int main(int argc, char **argv)
|
||||
graphicsApi = Vulkan;
|
||||
if (cmdLineParser.isSet(d3dOption))
|
||||
graphicsApi = D3D11;
|
||||
if (cmdLineParser.isSet(d3d12Option))
|
||||
graphicsApi = D3D12;
|
||||
if (cmdLineParser.isSet(mtlOption))
|
||||
graphicsApi = Metal;
|
||||
|
||||
|
@ -4,10 +4,6 @@
|
||||
#include "window.h"
|
||||
#include <QPlatformSurfaceEvent>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
extern QVulkanInstance *instance;
|
||||
#endif
|
||||
@ -25,6 +21,7 @@ Window::Window(const QString &title, GraphicsApi api)
|
||||
#endif
|
||||
break;
|
||||
case D3D11:
|
||||
case D3D12:
|
||||
setSurfaceType(Direct3DSurface);
|
||||
break;
|
||||
case Metal:
|
||||
|
@ -11,6 +11,7 @@ enum GraphicsApi
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Metal
|
||||
};
|
||||
|
||||
|
@ -7,27 +7,10 @@
|
||||
#include <QFile>
|
||||
#include <QLoggingCategory>
|
||||
#include <QCommandLineParser>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
|
||||
#include <QtGui/private/qrhinull_p.h>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QLoggingCategory>
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtGui/private/qrhid3d11_p.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#endif
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
//#define TEST_FINISH
|
||||
|
||||
@ -51,6 +34,7 @@ enum GraphicsApi
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Metal,
|
||||
Null
|
||||
};
|
||||
@ -66,6 +50,8 @@ QString graphicsApiName()
|
||||
return QLatin1String("Vulkan");
|
||||
case D3D11:
|
||||
return QLatin1String("Direct3D 11");
|
||||
case D3D12:
|
||||
return QLatin1String("Direct3D 12");
|
||||
case Metal:
|
||||
return QLatin1String("Metal");
|
||||
case Null:
|
||||
@ -96,8 +82,10 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(glOption);
|
||||
QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
|
||||
cmdLineParser.addOption(vkOption);
|
||||
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3dOption);
|
||||
QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3d11Option);
|
||||
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
|
||||
cmdLineParser.addOption(d3d12Option);
|
||||
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
|
||||
cmdLineParser.addOption(mtlOption);
|
||||
QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null"));
|
||||
@ -107,8 +95,10 @@ int main(int argc, char **argv)
|
||||
graphicsApi = OpenGL;
|
||||
if (cmdLineParser.isSet(vkOption))
|
||||
graphicsApi = Vulkan;
|
||||
if (cmdLineParser.isSet(d3dOption))
|
||||
if (cmdLineParser.isSet(d3d11Option))
|
||||
graphicsApi = D3D11;
|
||||
if (cmdLineParser.isSet(d3d12Option))
|
||||
graphicsApi = D3D12;
|
||||
if (cmdLineParser.isSet(mtlOption))
|
||||
graphicsApi = Metal;
|
||||
if (cmdLineParser.isSet(nullOption))
|
||||
@ -118,10 +108,11 @@ int main(int argc, char **argv)
|
||||
qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText()));
|
||||
|
||||
QRhi *r = nullptr;
|
||||
QRhi::Flags rhiFlags = QRhi::EnableTimestamps;
|
||||
|
||||
if (graphicsApi == Null) {
|
||||
QRhiNullInitParams params;
|
||||
r = QRhi::create(QRhi::Null, ¶ms);
|
||||
r = QRhi::create(QRhi::Null, ¶ms, rhiFlags);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
@ -133,7 +124,7 @@ int main(int argc, char **argv)
|
||||
if (inst.create()) {
|
||||
QRhiVulkanInitParams params;
|
||||
params.inst = &inst;
|
||||
r = QRhi::create(QRhi::Vulkan, ¶ms);
|
||||
r = QRhi::create(QRhi::Vulkan, ¶ms, rhiFlags);
|
||||
} else {
|
||||
qWarning("Failed to create Vulkan instance, switching to OpenGL");
|
||||
graphicsApi = OpenGL;
|
||||
@ -147,7 +138,7 @@ int main(int argc, char **argv)
|
||||
offscreenSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
||||
QRhiGles2InitParams params;
|
||||
params.fallbackSurface = offscreenSurface.data();
|
||||
r = QRhi::create(QRhi::OpenGLES2, ¶ms);
|
||||
r = QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -155,14 +146,18 @@ int main(int argc, char **argv)
|
||||
if (graphicsApi == D3D11) {
|
||||
QRhiD3D11InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r = QRhi::create(QRhi::D3D11, ¶ms);
|
||||
r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags);
|
||||
} else if (graphicsApi == D3D12) {
|
||||
QRhiD3D12InitParams params;
|
||||
params.enableDebugLayer = true;
|
||||
r = QRhi::create(QRhi::D3D12, ¶ms, rhiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
if (graphicsApi == Metal) {
|
||||
QRhiMetalInitParams params;
|
||||
r = QRhi::create(QRhi::Metal, ¶ms);
|
||||
r = QRhi::create(QRhi::Metal, ¶ms, rhiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -289,6 +284,8 @@ int main(int argc, char **argv)
|
||||
#ifdef TEST_FINISH
|
||||
r->endOffscreenFrame();
|
||||
#endif
|
||||
if (r->isFeatureSupported(QRhi::Timestamps))
|
||||
qDebug() << "GPU time:" << cb->lastCompletedGpuTime() << "seconds (may refer to a previous frame)";
|
||||
}
|
||||
|
||||
delete ps;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#define EXAMPLEWIDGET_H
|
||||
|
||||
#include "rhiwidget.h"
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class ExampleRhiWidget : public QRhiWidget
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
#define RHIWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class QRhiWidgetPrivate;
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
* Author: Bill Hollings <bill.hollings@brenwill.com>
|
||||
*/
|
||||
|
||||
// Normals added by Qt.
|
||||
|
||||
#ifndef CUBE_H
|
||||
#define CUBE_H
|
||||
|
||||
@ -72,6 +74,7 @@ static const float cube[] = {
|
||||
1.0f,-1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
|
||||
// UVs
|
||||
0.0f, 1.0f, // -X side
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
@ -113,6 +116,49 @@ static const float cube[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
|
||||
// normals
|
||||
-1.0, 0.0, 0.0, // -X side
|
||||
-1.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
|
||||
0.0, 0.0, -1.0, // -Z side
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 0.0, -1.0,
|
||||
|
||||
0.0, -1.0, 0.0, // -Y side
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
|
||||
0.0, 1.0, 0.0, // +Y side
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
|
||||
1.0, 0.0, 0.0, // +X side
|
||||
1.0, 0.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
|
||||
0.0, 0.0, 1.0, // +Z side
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 1.0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -13,26 +13,13 @@
|
||||
#include <QTimer>
|
||||
#include <QLoggingCategory>
|
||||
#include <QColorSpace>
|
||||
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qrhinull_p.h>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
#include <QtGui/private/qrhivulkan_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtGui/private/qrhid3d11_p.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
#include "qrhiimgui_p.h"
|
||||
#include "imgui.h"
|
||||
#endif
|
||||
|
||||
QShader getShader(const QString &name)
|
||||
@ -44,12 +31,22 @@ QShader getShader(const QString &name)
|
||||
return QShader();
|
||||
}
|
||||
|
||||
QByteArray getResource(const QString &name)
|
||||
{
|
||||
QFile f(name);
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
return f.readAll();
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
enum GraphicsApi
|
||||
{
|
||||
Null,
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Metal
|
||||
};
|
||||
|
||||
@ -66,6 +63,8 @@ QString graphicsApiName()
|
||||
return QLatin1String("Vulkan");
|
||||
case D3D11:
|
||||
return QLatin1String("Direct3D 11");
|
||||
case D3D12:
|
||||
return QLatin1String("Direct3D 12");
|
||||
case Metal:
|
||||
return QLatin1String("Metal");
|
||||
default:
|
||||
@ -74,12 +73,11 @@ QString graphicsApiName()
|
||||
return QString();
|
||||
}
|
||||
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers | QRhi::EnableTimestamps;
|
||||
int sampleCount = 1;
|
||||
QRhiSwapChain::Flags scFlags;
|
||||
QRhi::BeginFrameFlags beginFrameFlags;
|
||||
QRhi::EndFrameFlags endFrameFlags;
|
||||
int framesUntilTdr = -1;
|
||||
bool transparentBackground = false;
|
||||
bool debugLayer = true;
|
||||
|
||||
@ -99,6 +97,9 @@ protected:
|
||||
void customInit();
|
||||
void customRelease();
|
||||
void customRender();
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
void customGui();
|
||||
#endif
|
||||
|
||||
void exposeEvent(QExposeEvent *) override;
|
||||
bool event(QEvent *) override;
|
||||
@ -127,6 +128,11 @@ protected:
|
||||
|
||||
QColor m_clearColor;
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
QRhiImguiRenderer *m_imguiRenderer;
|
||||
QRhiImgui m_imgui;
|
||||
#endif
|
||||
|
||||
friend int main(int, char**);
|
||||
};
|
||||
|
||||
@ -141,6 +147,7 @@ Window::Window()
|
||||
setSurfaceType(VulkanSurface);
|
||||
break;
|
||||
case D3D11:
|
||||
case D3D12:
|
||||
setSurfaceType(Direct3DSurface);
|
||||
break;
|
||||
case Metal:
|
||||
@ -200,6 +207,10 @@ bool Window::event(QEvent *e)
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
if (m_imgui.processEvent(e))
|
||||
return true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@ -238,11 +249,13 @@ void Window::init()
|
||||
if (debugLayer)
|
||||
qDebug("Enabling D3D11 debug layer");
|
||||
params.enableDebugLayer = debugLayer;
|
||||
if (framesUntilTdr > 0) {
|
||||
params.framesUntilKillingDeviceViaTdr = framesUntilTdr;
|
||||
params.repeatDeviceKill = true;
|
||||
}
|
||||
m_r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags);
|
||||
} else if (graphicsApi == D3D12) {
|
||||
QRhiD3D12InitParams params;
|
||||
if (debugLayer)
|
||||
qDebug("Enabling D3D12 debug layer");
|
||||
params.enableDebugLayer = debugLayer;
|
||||
m_r = QRhi::create(QRhi::D3D12, ¶ms, rhiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -270,6 +283,21 @@ void Window::init()
|
||||
m_rp = m_sc->newCompatibleRenderPassDescriptor();
|
||||
m_sc->setRenderPassDescriptor(m_rp);
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
io.FontAllowUserScaling = true; // enable ctrl+wheel on windows
|
||||
io.IniFilename = nullptr; // no imgui.ini
|
||||
|
||||
QByteArray font = getResource(QLatin1String(":/fonts/RobotoMono-Medium.ttf"));
|
||||
ImFontConfig fontCfg;
|
||||
fontCfg.FontDataOwnedByAtlas = false;
|
||||
io.Fonts->Clear();
|
||||
io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), 20.0f, &fontCfg);
|
||||
m_imgui.rebuildFontAtlas();
|
||||
|
||||
m_imguiRenderer = new QRhiImguiRenderer;
|
||||
#endif
|
||||
|
||||
customInit();
|
||||
}
|
||||
|
||||
@ -286,6 +314,11 @@ void Window::releaseResources()
|
||||
delete m_sc;
|
||||
m_sc = nullptr;
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
delete m_imguiRenderer;
|
||||
m_imguiRenderer = nullptr;
|
||||
#endif
|
||||
|
||||
delete m_r;
|
||||
m_r = nullptr;
|
||||
|
||||
@ -354,6 +387,20 @@ void Window::render()
|
||||
m_frameCount = 0;
|
||||
}
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
m_imgui.nextFrame(size(), devicePixelRatio(), QPointF(0, 0), std::bind(&Window::customGui, this));
|
||||
m_imgui.syncRenderer(m_imguiRenderer);
|
||||
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiRenderTarget *rt = m_sc->currentFrameRenderTarget();
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
const float dpr = devicePixelRatio();
|
||||
|
||||
QMatrix4x4 guiMvp = m_r->clipSpaceCorrMatrix();
|
||||
guiMvp.ortho(0, outputSizeInPixels.width() / dpr, outputSizeInPixels.height() / dpr, 0, 1, -1);
|
||||
m_imguiRenderer->prepare(m_r, rt, cb, guiMvp, 1.0f);
|
||||
#endif
|
||||
|
||||
customRender();
|
||||
|
||||
m_r->endFrame(m_sc, endFrameFlags);
|
||||
@ -390,8 +437,10 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(glOption);
|
||||
QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
|
||||
cmdLineParser.addOption(vkOption);
|
||||
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3dOption);
|
||||
QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
|
||||
cmdLineParser.addOption(d3d11Option);
|
||||
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
|
||||
cmdLineParser.addOption(d3d12Option);
|
||||
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
|
||||
cmdLineParser.addOption(mtlOption);
|
||||
// Testing cleanup both with QWindow::close() (hitting X or Alt-F4) and
|
||||
@ -401,12 +450,7 @@ int main(int argc, char **argv)
|
||||
cmdLineParser.addOption(sdOption);
|
||||
QCommandLineOption coreProfOption({ "c", "core" }, QLatin1String("Request a core profile context for OpenGL"));
|
||||
cmdLineParser.addOption(coreProfOption);
|
||||
// Attempt testing device lost situations on D3D at least.
|
||||
QCommandLineOption tdrOption(QLatin1String("curse"), QLatin1String("Curse the graphics device. "
|
||||
"(generate a device reset every <count> frames when on D3D11)"),
|
||||
QLatin1String("count"));
|
||||
cmdLineParser.addOption(tdrOption);
|
||||
// Allow testing preferring the software adapter (D3D).
|
||||
// Allow testing preferring the software adapter (D3D, Vulkan).
|
||||
QCommandLineOption swOption(QLatin1String("software"), QLatin1String("Prefer a software renderer when choosing the adapter. "
|
||||
"Only applicable with some APIs and platforms."));
|
||||
cmdLineParser.addOption(swOption);
|
||||
@ -421,8 +465,10 @@ int main(int argc, char **argv)
|
||||
graphicsApi = OpenGL;
|
||||
if (cmdLineParser.isSet(vkOption))
|
||||
graphicsApi = Vulkan;
|
||||
if (cmdLineParser.isSet(d3dOption))
|
||||
if (cmdLineParser.isSet(d3d11Option))
|
||||
graphicsApi = D3D11;
|
||||
if (cmdLineParser.isSet(d3d12Option))
|
||||
graphicsApi = D3D12;
|
||||
if (cmdLineParser.isSet(mtlOption))
|
||||
graphicsApi = Metal;
|
||||
|
||||
@ -471,11 +517,14 @@ int main(int argc, char **argv)
|
||||
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
|
||||
}
|
||||
const QVersionNumber supportedVersion = inst.supportedApiVersion();
|
||||
qDebug() << "Supported Vulkan API version:" << supportedVersion;
|
||||
if (supportedVersion >= QVersionNumber(1, 1)) {
|
||||
qDebug("Requesting Vulkan API 1.1 on the VkInstance");
|
||||
if (supportedVersion >= QVersionNumber(1, 3))
|
||||
inst.setApiVersion(QVersionNumber(1, 3));
|
||||
else if (supportedVersion >= QVersionNumber(1, 2))
|
||||
inst.setApiVersion(QVersionNumber(1, 2));
|
||||
else if (supportedVersion >= QVersionNumber(1, 1))
|
||||
inst.setApiVersion(QVersionNumber(1, 1));
|
||||
}
|
||||
qDebug() << "Requesting Vulkan API" << inst.apiVersion().toString();
|
||||
qDebug() << "Instance-level version was reported as" << supportedVersion.toString();
|
||||
inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
|
||||
if (!inst.create()) {
|
||||
qWarning("Failed to create Vulkan instance, switching to OpenGL");
|
||||
@ -484,9 +533,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmdLineParser.isSet(tdrOption))
|
||||
framesUntilTdr = cmdLineParser.value(tdrOption).toInt();
|
||||
|
||||
if (cmdLineParser.isSet(swOption))
|
||||
rhiFlags |= QRhi::PreferSoftwareRenderer;
|
||||
|
||||
|
2
tests/manual/rhi/shared/imgui/buildshaders.bat
Normal file
2
tests/manual/rhi/shared/imgui/buildshaders.bat
Normal file
@ -0,0 +1,2 @@
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.vert -o imgui.vert.qsb
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.frag -o imgui.frag.qsb
|
202
tests/manual/rhi/shared/imgui/fonts/LICENSE.txt
Normal file
202
tests/manual/rhi/shared/imgui/fonts/LICENSE.txt
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
tests/manual/rhi/shared/imgui/fonts/RobotoMono-Medium.ttf
Normal file
BIN
tests/manual/rhi/shared/imgui/fonts/RobotoMono-Medium.ttf
Normal file
Binary file not shown.
29
tests/manual/rhi/shared/imgui/imgui.cmakeinc
Normal file
29
tests/manual/rhi/shared/imgui/imgui.cmakeinc
Normal file
@ -0,0 +1,29 @@
|
||||
set(imgui_sources
|
||||
${imgui_base}/imgui/imgui.cpp
|
||||
${imgui_base}/imgui/imgui_draw.cpp
|
||||
${imgui_base}/imgui/imgui_tables.cpp
|
||||
${imgui_base}/imgui/imgui_widgets.cpp
|
||||
${imgui_base}/imgui/imgui_demo.cpp
|
||||
${imgui_base}/qrhiimgui.cpp
|
||||
${imgui_base}/qrhiimgui_p.h
|
||||
)
|
||||
|
||||
target_sources(${imgui_target} PRIVATE
|
||||
${imgui_sources}
|
||||
)
|
||||
|
||||
target_include_directories(${imgui_target} PRIVATE
|
||||
${imgui_base}
|
||||
${imgui_base}/imgui
|
||||
)
|
||||
|
||||
qt6_add_resources(${imgui_target} "imgui_resources"
|
||||
PREFIX
|
||||
"/"
|
||||
BASE
|
||||
${imgui_base}
|
||||
FILES
|
||||
${imgui_base}/imgui.vert.qsb
|
||||
${imgui_base}/imgui.frag.qsb
|
||||
${imgui_base}/fonts/RobotoMono-Medium.ttf
|
||||
)
|
21
tests/manual/rhi/shared/imgui/imgui.frag
Normal file
21
tests/manual/rhi/shared/imgui/imgui.frag
Normal file
@ -0,0 +1,21 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec2 v_texcoord;
|
||||
layout(location = 1) in vec4 v_color;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
layout(binding = 1) uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = v_color * texture(tex, v_texcoord);
|
||||
c.a *= opacity;
|
||||
c.rgb *= c.a;
|
||||
fragColor = c;
|
||||
}
|
BIN
tests/manual/rhi/shared/imgui/imgui.frag.qsb
Normal file
BIN
tests/manual/rhi/shared/imgui/imgui.frag.qsb
Normal file
Binary file not shown.
20
tests/manual/rhi/shared/imgui/imgui.vert
Normal file
20
tests/manual/rhi/shared/imgui/imgui.vert
Normal file
@ -0,0 +1,20 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 1) in vec2 texcoord;
|
||||
layout(location = 2) in vec4 color;
|
||||
|
||||
layout(location = 0) out vec2 v_texcoord;
|
||||
layout(location = 1) out vec4 v_color;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
v_texcoord = texcoord;
|
||||
v_color = color;
|
||||
gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/shared/imgui/imgui.vert.qsb
Normal file
BIN
tests/manual/rhi/shared/imgui/imgui.vert.qsb
Normal file
Binary file not shown.
21
tests/manual/rhi/shared/imgui/imgui/LICENSE.txt
Normal file
21
tests/manual/rhi/shared/imgui/imgui/LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2022 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
125
tests/manual/rhi/shared/imgui/imgui/imconfig.h
Normal file
125
tests/manual/rhi/shared/imgui/imgui/imconfig.h
Normal file
@ -0,0 +1,125 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||
// This adds a small runtime cost which is why it is not enabled by default.
|
||||
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
13444
tests/manual/rhi/shared/imgui/imgui/imgui.cpp
Normal file
13444
tests/manual/rhi/shared/imgui/imgui/imgui.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3065
tests/manual/rhi/shared/imgui/imgui/imgui.h
Normal file
3065
tests/manual/rhi/shared/imgui/imgui/imgui.h
Normal file
File diff suppressed because it is too large
Load Diff
7969
tests/manual/rhi/shared/imgui/imgui/imgui_demo.cpp
Normal file
7969
tests/manual/rhi/shared/imgui/imgui/imgui_demo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4162
tests/manual/rhi/shared/imgui/imgui/imgui_draw.cpp
Normal file
4162
tests/manual/rhi/shared/imgui/imgui/imgui_draw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2975
tests/manual/rhi/shared/imgui/imgui/imgui_internal.h
Normal file
2975
tests/manual/rhi/shared/imgui/imgui/imgui_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
4068
tests/manual/rhi/shared/imgui/imgui/imgui_tables.cpp
Normal file
4068
tests/manual/rhi/shared/imgui/imgui/imgui_tables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
8394
tests/manual/rhi/shared/imgui/imgui/imgui_widgets.cpp
Normal file
8394
tests/manual/rhi/shared/imgui/imgui/imgui_widgets.cpp
Normal file
File diff suppressed because it is too large
Load Diff
627
tests/manual/rhi/shared/imgui/imgui/imstb_rectpack.h
Normal file
627
tests/manual/rhi/shared/imgui/imgui/imstb_rectpack.h
Normal file
@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
1447
tests/manual/rhi/shared/imgui/imgui/imstb_textedit.h
Normal file
1447
tests/manual/rhi/shared/imgui/imgui/imstb_textedit.h
Normal file
File diff suppressed because it is too large
Load Diff
5085
tests/manual/rhi/shared/imgui/imgui/imstb_truetype.h
Normal file
5085
tests/manual/rhi/shared/imgui/imgui/imstb_truetype.h
Normal file
File diff suppressed because it is too large
Load Diff
606
tests/manual/rhi/shared/imgui/qrhiimgui.cpp
Normal file
606
tests/manual/rhi/shared/imgui/qrhiimgui.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "qrhiimgui_p.h"
|
||||
#include <QtCore/qfile.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qclipboard.h>
|
||||
#include <QtGui/qimage.h>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
// the imgui default
|
||||
static_assert(sizeof(ImDrawVert) == 20);
|
||||
// switched to uint in imconfig.h to avoid trouble with 4 byte offset alignment reqs
|
||||
static_assert(sizeof(ImDrawIdx) == 4);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QShader getShader(const QString &name)
|
||||
{
|
||||
QFile f(name);
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
return QShader::fromSerialized(f.readAll());
|
||||
|
||||
return QShader();
|
||||
}
|
||||
|
||||
QRhiImguiRenderer::~QRhiImguiRenderer()
|
||||
{
|
||||
releaseResources();
|
||||
}
|
||||
|
||||
void QRhiImguiRenderer::releaseResources()
|
||||
{
|
||||
for (Texture &t : m_textures) {
|
||||
delete t.tex;
|
||||
delete t.srb;
|
||||
}
|
||||
m_textures.clear();
|
||||
|
||||
m_vbuf.reset();
|
||||
m_ibuf.reset();
|
||||
m_ubuf.reset();
|
||||
m_ps.reset();
|
||||
m_sampler.reset();
|
||||
|
||||
m_rhi = nullptr;
|
||||
}
|
||||
|
||||
void QRhiImguiRenderer::prepare(QRhi *rhi, QRhiRenderTarget *rt, QRhiCommandBuffer *cb, const QMatrix4x4 &mvp, float opacity)
|
||||
{
|
||||
if (!m_rhi) {
|
||||
m_rhi = rhi;
|
||||
} else if (m_rhi != rhi) {
|
||||
releaseResources();
|
||||
m_rhi = rhi;
|
||||
}
|
||||
|
||||
if (!m_rhi || f.draw.isEmpty())
|
||||
return;
|
||||
|
||||
m_rt = rt;
|
||||
m_cb = cb;
|
||||
|
||||
if (!m_vbuf) {
|
||||
m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, f.totalVbufSize));
|
||||
m_vbuf->setName(QByteArrayLiteral("imgui vertex buffer"));
|
||||
if (!m_vbuf->create())
|
||||
return;
|
||||
} else {
|
||||
if (f.totalVbufSize > m_vbuf->size()) {
|
||||
m_vbuf->setSize(f.totalVbufSize);
|
||||
if (!m_vbuf->create())
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!m_ibuf) {
|
||||
m_ibuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::IndexBuffer, f.totalIbufSize));
|
||||
m_ibuf->setName(QByteArrayLiteral("imgui index buffer"));
|
||||
if (!m_ibuf->create())
|
||||
return;
|
||||
} else {
|
||||
if (f.totalIbufSize > m_ibuf->size()) {
|
||||
m_ibuf->setSize(f.totalIbufSize);
|
||||
if (!m_ibuf->create())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_ubuf) {
|
||||
m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4));
|
||||
m_ubuf->setName(QByteArrayLiteral("imgui uniform buffer"));
|
||||
if (!m_ubuf->create())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_sampler) {
|
||||
m_sampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
QRhiSampler::Repeat, QRhiSampler::Repeat));
|
||||
m_sampler->setName(QByteArrayLiteral("imgui sampler"));
|
||||
if (!m_sampler->create())
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_textures.isEmpty()) {
|
||||
Texture fontTex;
|
||||
fontTex.image = sf.fontTextureData;
|
||||
m_textures.append(fontTex);
|
||||
} else if (!sf.fontTextureData.isNull()) {
|
||||
Texture fontTex;
|
||||
fontTex.image = sf.fontTextureData;
|
||||
delete m_textures[0].tex;
|
||||
delete m_textures[0].srb;
|
||||
m_textures[0] = fontTex;
|
||||
}
|
||||
|
||||
QVarLengthArray<int, 8> texturesNeedUpdate;
|
||||
for (int i = 0; i < m_textures.count(); ++i) {
|
||||
Texture &t(m_textures[i]);
|
||||
if (!t.tex) {
|
||||
t.tex = m_rhi->newTexture(QRhiTexture::RGBA8, t.image.size());
|
||||
t.tex->setName(QByteArrayLiteral("imgui texture ") + QByteArray::number(i));
|
||||
if (!t.tex->create())
|
||||
return;
|
||||
texturesNeedUpdate.append(i);
|
||||
}
|
||||
if (!t.srb) {
|
||||
t.srb = m_rhi->newShaderResourceBindings();
|
||||
t.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf.get()),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, t.tex, m_sampler.get())
|
||||
});
|
||||
if (!t.srb->create())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If layer.enabled is toggled on the item or an ancestor, the render
|
||||
// target is then suddenly different and may not be compatible.
|
||||
if (m_ps && m_rt->renderPassDescriptor()->serializedFormat() != m_renderPassFormat)
|
||||
m_ps.reset();
|
||||
|
||||
if (!m_ps) {
|
||||
QShader vs = getShader(QLatin1String(":/imgui.vert.qsb"));
|
||||
QShader fs = getShader(QLatin1String(":/imgui.frag.qsb"));
|
||||
if (!vs.isValid() || !fs.isValid()) {
|
||||
qWarning("Failed to load imgui shaders");
|
||||
return;
|
||||
}
|
||||
|
||||
m_ps.reset(m_rhi->newGraphicsPipeline());
|
||||
QRhiGraphicsPipeline::TargetBlend blend;
|
||||
blend.enable = true;
|
||||
// Premultiplied alpha (matches imgui.frag). Would not be needed if we
|
||||
// only cared about outputting to the window (the common case), but
|
||||
// once going through a texture (Item layer, ShaderEffect) which is
|
||||
// then sampled by Quick, the result wouldn't be correct otherwise.
|
||||
blend.srcColor = QRhiGraphicsPipeline::One;
|
||||
blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
|
||||
blend.srcAlpha = QRhiGraphicsPipeline::One;
|
||||
blend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
|
||||
m_ps->setTargetBlends({ blend });
|
||||
m_ps->setCullMode(QRhiGraphicsPipeline::None);
|
||||
m_ps->setDepthTest(true);
|
||||
m_ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual);
|
||||
m_ps->setDepthWrite(false);
|
||||
m_ps->setFlags(QRhiGraphicsPipeline::UsesScissor);
|
||||
|
||||
m_ps->setShaderStages({
|
||||
{ QRhiShaderStage::Vertex, vs },
|
||||
{ QRhiShaderStage::Fragment, fs }
|
||||
});
|
||||
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 4 * sizeof(float) + sizeof(quint32) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) },
|
||||
{ 0, 2, QRhiVertexInputAttribute::UNormByte4, 4 * sizeof(float) }
|
||||
});
|
||||
|
||||
m_ps->setVertexInputLayout(inputLayout);
|
||||
m_ps->setShaderResourceBindings(m_textures[0].srb);
|
||||
m_ps->setRenderPassDescriptor(m_rt->renderPassDescriptor());
|
||||
m_renderPassFormat = m_rt->renderPassDescriptor()->serializedFormat();
|
||||
|
||||
if (!m_ps->create())
|
||||
return;
|
||||
}
|
||||
|
||||
QRhiResourceUpdateBatch *u = m_rhi->nextResourceUpdateBatch();
|
||||
|
||||
for (const CmdListBuffer &b : f.vbuf)
|
||||
u->updateDynamicBuffer(m_vbuf.get(), b.offset, b.data.size(), b.data.constData());
|
||||
|
||||
for (const CmdListBuffer &b : f.ibuf)
|
||||
u->updateDynamicBuffer(m_ibuf.get(), b.offset, b.data.size(), b.data.constData());
|
||||
|
||||
u->updateDynamicBuffer(m_ubuf.get(), 0, 64, mvp.constData());
|
||||
u->updateDynamicBuffer(m_ubuf.get(), 64, 4, &opacity);
|
||||
|
||||
for (int i = 0; i < texturesNeedUpdate.count(); ++i) {
|
||||
Texture &t(m_textures[texturesNeedUpdate[i]]);
|
||||
u->uploadTexture(t.tex, t.image);
|
||||
t.image = QImage();
|
||||
}
|
||||
|
||||
m_cb->resourceUpdate(u);
|
||||
}
|
||||
|
||||
void QRhiImguiRenderer::render()
|
||||
{
|
||||
if (!m_rhi || f.draw.isEmpty() || !m_ps)
|
||||
return;
|
||||
|
||||
m_cb->setGraphicsPipeline(m_ps.get());
|
||||
|
||||
const QSize viewportSize = m_rt->pixelSize();
|
||||
bool needsViewport = true;
|
||||
|
||||
for (const DrawCmd &c : f.draw) {
|
||||
QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), f.vbuf[c.cmdListBufferIdx].offset);
|
||||
if (needsViewport) {
|
||||
needsViewport = false;
|
||||
m_cb->setViewport({ 0, 0, float(viewportSize.width()), float(viewportSize.height()) });
|
||||
}
|
||||
const float sx1 = c.clipRect.x() + c.itemPixelOffset.x();
|
||||
const float sy1 = c.clipRect.y() + c.itemPixelOffset.y();
|
||||
const float sx2 = c.clipRect.z() + c.itemPixelOffset.x();
|
||||
const float sy2 = c.clipRect.w() + c.itemPixelOffset.y();
|
||||
QPoint scissorPos = QPointF(sx1, viewportSize.height() - sy2).toPoint();
|
||||
QSize scissorSize = QSizeF(sx2 - sx1, sy2 - sy1).toSize();
|
||||
scissorPos.setX(qMax(0, scissorPos.x()));
|
||||
scissorPos.setY(qMax(0, scissorPos.y()));
|
||||
scissorSize.setWidth(qMin(viewportSize.width(), scissorSize.width()));
|
||||
scissorSize.setHeight(qMin(viewportSize.height(), scissorSize.height()));
|
||||
m_cb->setScissor({ scissorPos.x(), scissorPos.y(), scissorSize.width(), scissorSize.height() });
|
||||
m_cb->setShaderResources(m_textures[c.textureIndex].srb);
|
||||
m_cb->setVertexInput(0, 1, &vbufBinding, m_ibuf.get(), c.indexOffset, QRhiCommandBuffer::IndexUInt32);
|
||||
m_cb->drawIndexed(c.elemCount);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *getClipboardText(void *)
|
||||
{
|
||||
static QByteArray contents;
|
||||
contents = QGuiApplication::clipboard()->text().toUtf8();
|
||||
return contents.constData();
|
||||
}
|
||||
|
||||
static void setClipboardText(void *, const char *text)
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
QRhiImgui::QRhiImgui()
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
rebuildFontAtlas();
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
io.GetClipboardTextFn = getClipboardText;
|
||||
io.SetClipboardTextFn = setClipboardText;
|
||||
}
|
||||
|
||||
QRhiImgui::~QRhiImgui()
|
||||
{
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void QRhiImgui::rebuildFontAtlas()
|
||||
{
|
||||
unsigned char *pixels;
|
||||
int w, h;
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &w, &h);
|
||||
const QImage wrapperImg(const_cast<const uchar *>(pixels), w, h, QImage::Format_RGBA8888);
|
||||
sf.fontTextureData = wrapperImg.copy();
|
||||
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(quintptr(0)));
|
||||
}
|
||||
|
||||
void QRhiImgui::nextFrame(const QSizeF &logicalOutputSize, float dpr, const QPointF &logicalOffset, FrameFunc frameFunc)
|
||||
{
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
|
||||
const QPointF itemPixelOffset = logicalOffset * dpr;
|
||||
f.outputPixelSize = (logicalOutputSize * dpr).toSize();
|
||||
io.DisplaySize.x = logicalOutputSize.width();
|
||||
io.DisplaySize.y = logicalOutputSize.height();
|
||||
io.DisplayFramebufferScale = ImVec2(dpr, dpr);
|
||||
|
||||
ImGui::NewFrame();
|
||||
if (frameFunc)
|
||||
frameFunc();
|
||||
ImGui::Render();
|
||||
|
||||
ImDrawData *draw = ImGui::GetDrawData();
|
||||
draw->ScaleClipRects(ImVec2(dpr, dpr));
|
||||
|
||||
f.vbuf.resize(draw->CmdListsCount);
|
||||
f.ibuf.resize(draw->CmdListsCount);
|
||||
f.totalVbufSize = 0;
|
||||
f.totalIbufSize = 0;
|
||||
for (int n = 0; n < draw->CmdListsCount; ++n) {
|
||||
const ImDrawList *cmdList = draw->CmdLists[n];
|
||||
const int vbufSize = cmdList->VtxBuffer.Size * sizeof(ImDrawVert);
|
||||
f.vbuf[n].offset = f.totalVbufSize;
|
||||
f.totalVbufSize += vbufSize;
|
||||
const int ibufSize = cmdList->IdxBuffer.Size * sizeof(ImDrawIdx);
|
||||
f.ibuf[n].offset = f.totalIbufSize;
|
||||
f.totalIbufSize += ibufSize;
|
||||
}
|
||||
f.draw.clear();
|
||||
for (int n = 0; n < draw->CmdListsCount; ++n) {
|
||||
const ImDrawList *cmdList = draw->CmdLists[n];
|
||||
f.vbuf[n].data = QByteArray(reinterpret_cast<const char *>(cmdList->VtxBuffer.Data),
|
||||
cmdList->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
f.ibuf[n].data = QByteArray(reinterpret_cast<const char *>(cmdList->IdxBuffer.Data),
|
||||
cmdList->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
const ImDrawIdx *indexBufOffset = nullptr;
|
||||
for (int i = 0; i < cmdList->CmdBuffer.Size; ++i) {
|
||||
const ImDrawCmd *cmd = &cmdList->CmdBuffer[i];
|
||||
const quint32 indexOffset = f.ibuf[n].offset + quintptr(indexBufOffset);
|
||||
if (!cmd->UserCallback) {
|
||||
QRhiImguiRenderer::DrawCmd dc;
|
||||
dc.cmdListBufferIdx = n;
|
||||
dc.textureIndex = int(reinterpret_cast<qintptr>(cmd->TextureId));
|
||||
dc.indexOffset = indexOffset;
|
||||
dc.elemCount = cmd->ElemCount;
|
||||
dc.itemPixelOffset = itemPixelOffset;
|
||||
dc.clipRect = QVector4D(cmd->ClipRect.x, cmd->ClipRect.y, cmd->ClipRect.z, cmd->ClipRect.w);
|
||||
f.draw.append(dc);
|
||||
} else {
|
||||
cmd->UserCallback(cmdList, cmd);
|
||||
}
|
||||
indexBufOffset += cmd->ElemCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QRhiImgui::syncRenderer(QRhiImguiRenderer *renderer)
|
||||
{
|
||||
renderer->sf = sf;
|
||||
sf.fontTextureData = QImage();
|
||||
renderer->f = std::move(f);
|
||||
}
|
||||
|
||||
static void updateKeyboardModifiers(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
io.AddKeyEvent(ImGuiKey_ModCtrl, modifiers.testFlag(Qt::ControlModifier));
|
||||
io.AddKeyEvent(ImGuiKey_ModShift, modifiers.testFlag(Qt::ShiftModifier));
|
||||
io.AddKeyEvent(ImGuiKey_ModAlt, modifiers.testFlag(Qt::AltModifier));
|
||||
io.AddKeyEvent(ImGuiKey_ModSuper, modifiers.testFlag(Qt::MetaModifier));
|
||||
}
|
||||
|
||||
static ImGuiKey mapKey(int k)
|
||||
{
|
||||
switch (k) {
|
||||
case Qt::Key_Space:
|
||||
return ImGuiKey_Space;
|
||||
case Qt::Key_Apostrophe:
|
||||
return ImGuiKey_Apostrophe;
|
||||
case Qt::Key_Comma:
|
||||
return ImGuiKey_Comma;
|
||||
case Qt::Key_Minus:
|
||||
return ImGuiKey_Minus;
|
||||
case Qt::Key_Period:
|
||||
return ImGuiKey_Period;
|
||||
case Qt::Key_Slash:
|
||||
return ImGuiKey_Slash;
|
||||
case Qt::Key_0:
|
||||
return ImGuiKey_0;
|
||||
case Qt::Key_1:
|
||||
return ImGuiKey_1;
|
||||
case Qt::Key_2:
|
||||
return ImGuiKey_2;
|
||||
case Qt::Key_3:
|
||||
return ImGuiKey_3;
|
||||
case Qt::Key_4:
|
||||
return ImGuiKey_4;
|
||||
case Qt::Key_5:
|
||||
return ImGuiKey_5;
|
||||
case Qt::Key_6:
|
||||
return ImGuiKey_6;
|
||||
case Qt::Key_7:
|
||||
return ImGuiKey_8;
|
||||
case Qt::Key_8:
|
||||
return ImGuiKey_8;
|
||||
case Qt::Key_9:
|
||||
return ImGuiKey_9;
|
||||
case Qt::Key_Semicolon:
|
||||
return ImGuiKey_Semicolon;
|
||||
case Qt::Key_Equal:
|
||||
return ImGuiKey_Equal;
|
||||
case Qt::Key_A:
|
||||
return ImGuiKey_A;
|
||||
case Qt::Key_B:
|
||||
return ImGuiKey_B;
|
||||
case Qt::Key_C:
|
||||
return ImGuiKey_C;
|
||||
case Qt::Key_D:
|
||||
return ImGuiKey_D;
|
||||
case Qt::Key_E:
|
||||
return ImGuiKey_E;
|
||||
case Qt::Key_F:
|
||||
return ImGuiKey_F;
|
||||
case Qt::Key_G:
|
||||
return ImGuiKey_G;
|
||||
case Qt::Key_H:
|
||||
return ImGuiKey_H;
|
||||
case Qt::Key_I:
|
||||
return ImGuiKey_I;
|
||||
case Qt::Key_J:
|
||||
return ImGuiKey_J;
|
||||
case Qt::Key_K:
|
||||
return ImGuiKey_K;
|
||||
case Qt::Key_L:
|
||||
return ImGuiKey_L;
|
||||
case Qt::Key_M:
|
||||
return ImGuiKey_M;
|
||||
case Qt::Key_N:
|
||||
return ImGuiKey_N;
|
||||
case Qt::Key_O:
|
||||
return ImGuiKey_O;
|
||||
case Qt::Key_P:
|
||||
return ImGuiKey_P;
|
||||
case Qt::Key_Q:
|
||||
return ImGuiKey_Q;
|
||||
case Qt::Key_R:
|
||||
return ImGuiKey_R;
|
||||
case Qt::Key_S:
|
||||
return ImGuiKey_S;
|
||||
case Qt::Key_T:
|
||||
return ImGuiKey_T;
|
||||
case Qt::Key_U:
|
||||
return ImGuiKey_U;
|
||||
case Qt::Key_V:
|
||||
return ImGuiKey_V;
|
||||
case Qt::Key_W:
|
||||
return ImGuiKey_W;
|
||||
case Qt::Key_X:
|
||||
return ImGuiKey_X;
|
||||
case Qt::Key_Y:
|
||||
return ImGuiKey_Y;
|
||||
case Qt::Key_Z:
|
||||
return ImGuiKey_Z;
|
||||
case Qt::Key_BracketLeft:
|
||||
return ImGuiKey_LeftBracket;
|
||||
case Qt::Key_Backslash:
|
||||
return ImGuiKey_Backslash;
|
||||
case Qt::Key_BracketRight:
|
||||
return ImGuiKey_RightBracket;
|
||||
case Qt::Key_QuoteLeft:
|
||||
return ImGuiKey_GraveAccent;
|
||||
case Qt::Key_Escape:
|
||||
return ImGuiKey_Escape;
|
||||
case Qt::Key_Tab:
|
||||
return ImGuiKey_Tab;
|
||||
case Qt::Key_Backspace:
|
||||
return ImGuiKey_Backspace;
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
return ImGuiKey_Enter;
|
||||
case Qt::Key_Insert:
|
||||
return ImGuiKey_Insert;
|
||||
case Qt::Key_Delete:
|
||||
return ImGuiKey_Delete;
|
||||
case Qt::Key_Pause:
|
||||
return ImGuiKey_Pause;
|
||||
case Qt::Key_Print:
|
||||
return ImGuiKey_PrintScreen;
|
||||
case Qt::Key_Home:
|
||||
return ImGuiKey_Home;
|
||||
case Qt::Key_End:
|
||||
return ImGuiKey_End;
|
||||
case Qt::Key_Left:
|
||||
return ImGuiKey_LeftArrow;
|
||||
case Qt::Key_Up:
|
||||
return ImGuiKey_UpArrow;
|
||||
case Qt::Key_Right:
|
||||
return ImGuiKey_RightArrow;
|
||||
case Qt::Key_Down:
|
||||
return ImGuiKey_DownArrow;
|
||||
case Qt::Key_PageUp:
|
||||
return ImGuiKey_PageUp;
|
||||
case Qt::Key_PageDown:
|
||||
return ImGuiKey_PageDown;
|
||||
case Qt::Key_Shift:
|
||||
return ImGuiKey_LeftShift;
|
||||
case Qt::Key_Control:
|
||||
return ImGuiKey_LeftCtrl;
|
||||
case Qt::Key_Meta:
|
||||
return ImGuiKey_LeftSuper;
|
||||
case Qt::Key_Alt:
|
||||
return ImGuiKey_LeftAlt;
|
||||
case Qt::Key_CapsLock:
|
||||
return ImGuiKey_CapsLock;
|
||||
case Qt::Key_NumLock:
|
||||
return ImGuiKey_NumLock;
|
||||
case Qt::Key_ScrollLock:
|
||||
return ImGuiKey_ScrollLock;
|
||||
case Qt::Key_F1:
|
||||
return ImGuiKey_F1;
|
||||
case Qt::Key_F2:
|
||||
return ImGuiKey_F2;
|
||||
case Qt::Key_F3:
|
||||
return ImGuiKey_F3;
|
||||
case Qt::Key_F4:
|
||||
return ImGuiKey_F4;
|
||||
case Qt::Key_F5:
|
||||
return ImGuiKey_F5;
|
||||
case Qt::Key_F6:
|
||||
return ImGuiKey_F6;
|
||||
case Qt::Key_F7:
|
||||
return ImGuiKey_F7;
|
||||
case Qt::Key_F8:
|
||||
return ImGuiKey_F8;
|
||||
case Qt::Key_F9:
|
||||
return ImGuiKey_F9;
|
||||
case Qt::Key_F10:
|
||||
return ImGuiKey_F10;
|
||||
case Qt::Key_F11:
|
||||
return ImGuiKey_F11;
|
||||
case Qt::Key_F12:
|
||||
return ImGuiKey_F12;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ImGuiKey_None;
|
||||
}
|
||||
|
||||
bool QRhiImgui::processEvent(QEvent *event)
|
||||
{
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
updateKeyboardModifiers(me->modifiers());
|
||||
Qt::MouseButtons buttons = me->buttons();
|
||||
if (buttons.testFlag(Qt::LeftButton) && !pressedMouseButtons.testFlag(Qt::LeftButton))
|
||||
io.AddMouseButtonEvent(0, true);
|
||||
if (buttons.testFlag(Qt::RightButton) && !pressedMouseButtons.testFlag(Qt::RightButton))
|
||||
io.AddMouseButtonEvent(1, true);
|
||||
if (buttons.testFlag(Qt::MiddleButton) && !pressedMouseButtons.testFlag(Qt::MiddleButton))
|
||||
io.AddMouseButtonEvent(2, true);
|
||||
pressedMouseButtons = buttons;
|
||||
}
|
||||
return true;
|
||||
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
Qt::MouseButtons buttons = me->buttons();
|
||||
if (!buttons.testFlag(Qt::LeftButton) && pressedMouseButtons.testFlag(Qt::LeftButton))
|
||||
io.AddMouseButtonEvent(0, false);
|
||||
if (!buttons.testFlag(Qt::RightButton) && pressedMouseButtons.testFlag(Qt::RightButton))
|
||||
io.AddMouseButtonEvent(1, false);
|
||||
if (!buttons.testFlag(Qt::MiddleButton) && pressedMouseButtons.testFlag(Qt::MiddleButton))
|
||||
io.AddMouseButtonEvent(2, false);
|
||||
pressedMouseButtons = buttons;
|
||||
}
|
||||
return true;
|
||||
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
const QPointF pos = me->position();
|
||||
io.AddMousePosEvent(pos.x(), pos.y());
|
||||
}
|
||||
return true;
|
||||
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
QWheelEvent *we = static_cast<QWheelEvent *>(event);
|
||||
QPointF wheel(we->angleDelta().x() / 120.0f, we->angleDelta().y() / 120.0f);
|
||||
io.AddMouseWheelEvent(wheel.x(), wheel.y());
|
||||
}
|
||||
return true;
|
||||
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
{
|
||||
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||
const bool down = event->type() == QEvent::KeyPress;
|
||||
updateKeyboardModifiers(ke->modifiers());
|
||||
io.AddKeyEvent(mapKey(ke->key()), down);
|
||||
if (down && !ke->text().isEmpty()) {
|
||||
const QByteArray text = ke->text().toUtf8();
|
||||
io.AddInputCharactersUTF8(text.constData());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
93
tests/manual/rhi/shared/imgui/qrhiimgui_p.h
Normal file
93
tests/manual/rhi/shared/imgui/qrhiimgui_p.h
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef QRHIIMGUI_P_H
|
||||
#define QRHIIMGUI_P_H
|
||||
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QEvent;
|
||||
|
||||
class QRhiImguiRenderer
|
||||
{
|
||||
public:
|
||||
~QRhiImguiRenderer();
|
||||
|
||||
struct CmdListBuffer {
|
||||
quint32 offset;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
struct DrawCmd {
|
||||
int cmdListBufferIdx;
|
||||
int textureIndex;
|
||||
quint32 indexOffset;
|
||||
quint32 elemCount;
|
||||
QPointF itemPixelOffset;
|
||||
QVector4D clipRect;
|
||||
};
|
||||
|
||||
struct StaticRenderData {
|
||||
QImage fontTextureData;
|
||||
};
|
||||
|
||||
struct FrameRenderData {
|
||||
quint32 totalVbufSize = 0;
|
||||
quint32 totalIbufSize = 0;
|
||||
QVarLengthArray<CmdListBuffer, 4> vbuf;
|
||||
QVarLengthArray<CmdListBuffer, 4> ibuf;
|
||||
QVarLengthArray<DrawCmd, 4> draw;
|
||||
QSize outputPixelSize;
|
||||
};
|
||||
|
||||
StaticRenderData sf;
|
||||
FrameRenderData f;
|
||||
|
||||
void prepare(QRhi *rhi, QRhiRenderTarget *rt, QRhiCommandBuffer *cb, const QMatrix4x4 &mvp, float opacity);
|
||||
void render();
|
||||
void releaseResources();
|
||||
|
||||
private:
|
||||
QRhi *m_rhi = nullptr;
|
||||
QRhiRenderTarget *m_rt = nullptr;
|
||||
QRhiCommandBuffer *m_cb = nullptr;
|
||||
|
||||
std::unique_ptr<QRhiBuffer> m_vbuf;
|
||||
std::unique_ptr<QRhiBuffer> m_ibuf;
|
||||
std::unique_ptr<QRhiBuffer> m_ubuf;
|
||||
std::unique_ptr<QRhiGraphicsPipeline> m_ps;
|
||||
QVector<quint32> m_renderPassFormat;
|
||||
std::unique_ptr<QRhiSampler> m_sampler;
|
||||
|
||||
struct Texture {
|
||||
QImage image;
|
||||
QRhiTexture *tex = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
};
|
||||
QVector<Texture> m_textures;
|
||||
};
|
||||
|
||||
class QRhiImgui
|
||||
{
|
||||
public:
|
||||
QRhiImgui();
|
||||
~QRhiImgui();
|
||||
|
||||
using FrameFunc = std::function<void()>;
|
||||
void nextFrame(const QSizeF &logicalOutputSize, float dpr, const QPointF &logicalOffset, FrameFunc frameFunc);
|
||||
void syncRenderer(QRhiImguiRenderer *renderer);
|
||||
bool processEvent(QEvent *e);
|
||||
|
||||
void rebuildFontAtlas();
|
||||
|
||||
private:
|
||||
QRhiImguiRenderer::StaticRenderData sf;
|
||||
QRhiImguiRenderer::FrameRenderData f;
|
||||
Qt::MouseButtons pressedMouseButtons;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@
|
||||
#include <QPlatformSurfaceEvent>
|
||||
#include <QTimer>
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
#include "../shared/cube.h"
|
||||
|
||||
Window::Window()
|
||||
@ -55,7 +55,7 @@ bool Window::event(QEvent *e)
|
||||
|
||||
void Window::init()
|
||||
{
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers | QRhi::EnableProfiling;
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
||||
|
||||
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
||||
QRhiGles2InitParams params;
|
||||
|
@ -5,8 +5,8 @@
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWindow>
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
#include <QOffscreenSurface>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class Window : public QWindow
|
||||
{
|
||||
|
@ -43,7 +43,9 @@ void Window::customInit()
|
||||
if (!m_r->isFeatureSupported(QRhi::TextureArrays))
|
||||
qFatal("Texture array objects are not supported by this backend");
|
||||
|
||||
d.texArr = m_r->newTextureArray(QRhiTexture::RGBA8, ARRAY_SIZE, QSize(512, 512));
|
||||
d.texArr = m_r->newTextureArray(QRhiTexture::RGBA8, ARRAY_SIZE, QSize(512, 512), 1,
|
||||
// mipmaps will be generated, to exercise that too
|
||||
QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips);
|
||||
d.releasePool << d.texArr;
|
||||
d.texArr->create();
|
||||
|
||||
@ -59,7 +61,9 @@ void Window::customInit()
|
||||
img.fill(Qt::yellow);
|
||||
d.initialUpdates->uploadTexture(d.texArr, QRhiTextureUploadDescription(QRhiTextureUploadEntry(3, 0, QRhiTextureSubresourceUploadDescription(img))));
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
d.initialUpdates->generateMips(d.texArr);
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
|
||||
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
|
||||
d.releasePool << d.sampler;
|
||||
d.sampler->create();
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "quadrenderer.h"
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
|
||||
// Renders a quad using indexed drawing. No QRhiGraphicsPipeline is created, it
|
||||
// expects to reuse the one created by TriangleRenderer. A separate
|
||||
|
@ -4,7 +4,7 @@
|
||||
#ifndef QUADRENDERER_H
|
||||
#define QUADRENDERER_H
|
||||
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class QuadRenderer
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "texturedcuberenderer.h"
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
|
||||
#include "../shared/cube.h"
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#ifndef TEXTUREDCUBERENDERER_H
|
||||
#define TEXTUREDCUBERENDERER_H
|
||||
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class TexturedCubeRenderer
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "triangleoncuberenderer.h"
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
|
||||
// toggle to test the preserved content (no clear) path
|
||||
const bool IMAGE_UNDER_OFFSCREEN_RENDERING = false;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "trianglerenderer.h"
|
||||
#include <QFile>
|
||||
#include <QtGui/private/qshader_p.h>
|
||||
#include <rhi/qshader.h>
|
||||
|
||||
//#define VBUF_IS_DYNAMIC
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#ifndef TRIANGLERENDERER_H
|
||||
#define TRIANGLERENDERER_H
|
||||
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
class TriangleRenderer
|
||||
{
|
||||
|
@ -35,7 +35,6 @@ struct {
|
||||
QSize lastOutputSize;
|
||||
int frameCount = 0;
|
||||
QFile profOut;
|
||||
QVarLengthArray<float, 64> gpuFrameTimes;
|
||||
QElapsedTimer gpuFrameTimePrintTimer;
|
||||
} d;
|
||||
|
||||
@ -136,20 +135,8 @@ void Window::customInit()
|
||||
// With Vulkan at least we should see some details from the memory allocator.
|
||||
qDebug() << m_r->statistics();
|
||||
|
||||
// Every two seconds try printing an average of the gpu frame times.
|
||||
// Every two seconds try printing last known gpu frame time.
|
||||
d.gpuFrameTimePrintTimer.start();
|
||||
m_r->addGpuFrameTimeCallback([](float elapsedMs) {
|
||||
d.gpuFrameTimes.append(elapsedMs);
|
||||
if (d.gpuFrameTimePrintTimer.elapsed() > 2000) {
|
||||
float at = 0.0f;
|
||||
for (float t : d.gpuFrameTimes)
|
||||
at += t;
|
||||
at /= d.gpuFrameTimes.count();
|
||||
qDebug() << "Average GPU frame time" << at;
|
||||
d.gpuFrameTimes.clear();
|
||||
d.gpuFrameTimePrintTimer.restart();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Window::customRelease()
|
||||
@ -170,6 +157,11 @@ void Window::customRender()
|
||||
const QSize outputSize = m_sc->currentPixelSize();
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
|
||||
if (d.gpuFrameTimePrintTimer.elapsed() > 2000) {
|
||||
qDebug() << "Last completed GPU frame time" << cb->lastCompletedGpuTime() << "seconds";
|
||||
d.gpuFrameTimePrintTimer.restart();
|
||||
}
|
||||
|
||||
if (outputSize != d.lastOutputSize) {
|
||||
d.triRenderer.resize(outputSize);
|
||||
if (!d.triangleOnly) {
|
||||
|
Reference in New Issue
Block a user