summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJean-Michaël Celerier <jean-michael.celerier@kdab.com>2020-04-17 15:32:44 +0200
committerJean-Michaël Celerier <jean-michael.celerier@kdab.com>2020-04-22 09:37:31 +0200
commit4d3cb0012c1c80520f87a8ca84b7f66484178a4e (patch)
treedfc97801dfa1662576c0f5e8ea85d8c5a408cc6e /src
parentdf4ec04dae8c0ce9fa3b27bc8e48eb2d36a20962 (diff)
rhi: Work needed for PBR material support in RHI
Change-Id: Id0e7d343083afcefd93f9d581917e14baa994b7f Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src')
-rw-r--r--src/extras/defaults/qmetalroughmaterial.cpp5
-rw-r--r--src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp252
-rw-r--r--src/plugins/renderers/rhi/graphicshelpers/submissioncontext_p.h26
-rw-r--r--src/plugins/renderers/rhi/renderer/rendercommand.cpp6
-rw-r--r--src/plugins/renderers/rhi/renderer/rendercommand_p.h2
-rw-r--r--src/plugins/renderers/rhi/renderer/renderer.cpp81
-rw-r--r--src/plugins/renderers/rhi/renderer/renderview.cpp42
-rw-r--r--src/plugins/renderers/rhi/renderer/renderview_p.h12
-rw-r--r--src/plugins/renderers/rhi/textures/texture.cpp91
-rw-r--r--src/render/render.pro1
-rw-r--r--src/render/shadergraph/qshadergenerator.cpp2
-rw-r--r--src/render/surfaces/surfaces.pri9
-rw-r--r--src/render/surfaces/vulkaninstance.cpp75
-rw-r--r--src/render/surfaces/vulkaninstance_p.h54
14 files changed, 501 insertions, 157 deletions
diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp
index 7aecfa65d..78e544ead 100644
--- a/src/extras/defaults/qmetalroughmaterial.cpp
+++ b/src/extras/defaults/qmetalroughmaterial.cpp
@@ -377,6 +377,7 @@ void QMetalRoughMaterial::setBaseColor(const QVariant &baseColor)
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
+ d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
}
void QMetalRoughMaterial::setMetalness(const QVariant &metalness)
@@ -401,6 +402,7 @@ void QMetalRoughMaterial::setMetalness(const QVariant &metalness)
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
+ d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
}
void QMetalRoughMaterial::setRoughness(const QVariant &roughness)
@@ -425,6 +427,7 @@ void QMetalRoughMaterial::setRoughness(const QVariant &roughness)
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
+ d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
}
void QMetalRoughMaterial::setAmbientOcclusion(const QVariant &ambientOcclusion)
@@ -445,6 +448,7 @@ void QMetalRoughMaterial::setAmbientOcclusion(const QVariant &ambientOcclusion)
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
+ d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
}
void QMetalRoughMaterial::setNormal(const QVariant &normal)
@@ -465,6 +469,7 @@ void QMetalRoughMaterial::setNormal(const QVariant &normal)
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
+ d->m_metalRoughRHIShaderBuilder->setEnabledLayers(layers);
}
void QMetalRoughMaterial::setTextureScale(float textureScale)
diff --git a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
index eac49f01a..748138540 100644
--- a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
+++ b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext.cpp
@@ -62,6 +62,8 @@
#include <Qt3DRender/private/attachmentpack_p.h>
#include <Qt3DRender/private/qbuffer_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
+#include <Qt3DRender/private/vulkaninstance_p.h>
+#include <QGuiApplication>
#include <texture_p.h>
#include <rendercommand_p.h>
#include <renderer_p.h>
@@ -91,6 +93,7 @@
#include <QtGui/private/qrhivulkan_p.h>
#include <QVulkanInstance>
#endif
+#include <bitset>
QT_BEGIN_NAMESPACE
@@ -489,9 +492,6 @@ SubmissionContext::SubmissionContext()
, m_rhi(nullptr)
, m_currentSwapChain(nullptr)
, m_currentRenderPassDescriptor(nullptr)
-#if QT_CONFIG(vulkan)
- , m_vkInstance(nullptr)
-#endif
#ifndef QT_NO_OPENGL
, m_fallbackSurface(nullptr)
#endif
@@ -537,34 +537,9 @@ void SubmissionContext::initialize()
#if QT_CONFIG(vulkan)
if (requestedApi == Qt3DRender::API::Vulkan) {
- if (!m_vkInstance) {
- m_vkInstance = new QVulkanInstance();
- m_ownsVkInstance = true;
-
-#ifndef Q_OS_ANDROID
- m_vkInstance->setLayers({ "VK_LAYER_LUNARG_standard_validation" });
-#else
- m_vkInstance->setLayers(QByteArrayList()
- << "VK_LAYER_GOOGLE_threading"
- << "VK_LAYER_LUNARG_parameter_validation"
- << "VK_LAYER_LUNARG_object_tracker"
- << "VK_LAYER_LUNARG_core_validation"
- << "VK_LAYER_LUNARG_image"
- << "VK_LAYER_LUNARG_swapchain"
- << "VK_LAYER_GOOGLE_unique_objects");
-#endif
-
- if (!m_vkInstance->create()) {
- qWarning("Failed to create Vulkan instance");
- }
- }
-
- Q_ASSERT(m_vkInstance);
- if (m_vkInstance->isValid()) {
- QRhiVulkanInitParams params;
- params.inst = m_vkInstance;
- m_rhi = QRhi::create(QRhi::Vulkan, &params, rhiFlags);
- }
+ QRhiVulkanInitParams params;
+ params.inst = &Qt3DRender::staticVulkanInstance();
+ m_rhi = QRhi::create(QRhi::Vulkan, &params, rhiFlags);
}
#endif
@@ -674,63 +649,38 @@ bool SubmissionContext::beginDrawing(QSurface *surface)
}
// Check if we have a swapchain for the Window, if not create one
- SwapChainInfo &swapChainInfo = m_swapChains[surface];
- QRhiSwapChain *swapChain = swapChainInfo.swapChain;
-
- if (swapChain == nullptr) {
- swapChain = m_rhi->newSwapChain();
- Q_ASSERT(surface->surfaceClass() == QSurface::Window);
- QWindow *window = static_cast<QWindow *>(surface);
- Q_ASSERT(window != nullptr);
- const int samples = format().samples();
-
- swapChain->setWindow(window);
- swapChain->setFlags(QRhiSwapChain::Flags {});
- swapChain->setSampleCount(samples);
-
- QRhiRenderBuffer *renderBuffer = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
- QSize(),
- samples,
- QRhiRenderBuffer::UsedWithSwapChainOnly);
- swapChain->setDepthStencil(renderBuffer);
-
- QRhiRenderPassDescriptor *renderPassDescriptor = swapChain->newCompatibleRenderPassDescriptor();
- swapChain->setRenderPassDescriptor(renderPassDescriptor);
-
- // Build swapChain the first time
- swapChain->buildOrResize();
-
- swapChainInfo.swapChain = swapChain;
- swapChainInfo.renderBuffer = renderBuffer;
- swapChainInfo.renderPassDescriptor = renderPassDescriptor;
- }
+ SwapChainInfo *swapChainInfo = swapChainForSurface(surface);
+ QRhiSwapChain *swapChain = swapChainInfo->swapChain;
// TO DO: Check if that's required all the time
{
// Rebuild RenderPassDescriptor
- swapChainInfo.renderBuffer->setPixelSize(surface->size());
- swapChainInfo.renderBuffer->build();
+ // TODO -> this is not necessary, swapChain->buildOrResize already does it
+ // swapChainInfo->renderBuffer->setPixelSize(surface->size());
+ // swapChainInfo->renderBuffer->build();
// Resize swapchain if needed
if (m_surface->size() != swapChain->surfacePixelSize())
- swapChain->buildOrResize();
+ {
+ bool couldRebuild = swapChain->buildOrResize();
+ if (!couldRebuild)
+ return false;
+ }
}
m_currentSwapChain = swapChain;
- m_currentRenderPassDescriptor = swapChainInfo.renderPassDescriptor;
+ m_currentRenderPassDescriptor = swapChainInfo->renderPassDescriptor;
// Begin Frame
- m_rhi->beginFrame(m_currentSwapChain);
+ const auto success = m_rhi->beginFrame(m_currentSwapChain);
- // Update Resource Update Batch
- m_currentUpdates = m_rhi->nextResourceUpdateBatch();
-
- return true;
+ return success == QRhi::FrameOpSuccess;
}
void SubmissionContext::endDrawing(bool swapBuffers)
{
m_rhi->endFrame(m_currentSwapChain, {});
+ m_currentUpdates = nullptr;
RHI_UNIMPLEMENTED;
//* if (swapBuffers)
@@ -1031,12 +981,6 @@ void SubmissionContext::releaseResources()
delete m_rhi;
m_rhi = nullptr;
-#if QT_CONFIG(vulkan)
- if (m_ownsVkInstance) {
- delete m_vkInstance;
- m_vkInstance = nullptr;
- }
-#endif
#ifndef QT_NO_OPENGL
delete m_fallbackSurface;
m_fallbackSurface = nullptr;
@@ -1276,6 +1220,50 @@ StateVariant *SubmissionContext::getState(RenderStateSet *ss, StateMask type) co
return nullptr;
}
+
+SubmissionContext::SwapChainInfo *SubmissionContext::swapChainForSurface(QSurface *surface) noexcept
+{
+ SwapChainInfo &swapChainInfo = m_swapChains[surface];
+ auto& swapChain = swapChainInfo.swapChain;
+
+ if (swapChain == nullptr) {
+ swapChain = m_rhi->newSwapChain();
+ Q_ASSERT(surface->surfaceClass() == QSurface::Window);
+ QWindow *window = static_cast<QWindow *>(surface);
+ Q_ASSERT(window != nullptr);
+ const int samples = format().samples();
+
+
+ swapChain->setWindow(window);
+ swapChain->setFlags(QRhiSwapChain::Flags {});
+ swapChain->setSampleCount(samples);
+
+ QRhiRenderBuffer *renderBuffer = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
+ QSize(),
+ samples,
+ QRhiRenderBuffer::UsedWithSwapChainOnly);
+ swapChain->setDepthStencil(renderBuffer);
+
+ QRhiRenderPassDescriptor *renderPassDescriptor = swapChain->newCompatibleRenderPassDescriptor();
+ swapChain->setRenderPassDescriptor(renderPassDescriptor);
+
+ // Build swapChain the first time
+ if (swapChain->buildOrResize())
+ {
+ swapChainInfo.swapChain = swapChain;
+ swapChainInfo.renderBuffer = renderBuffer;
+ swapChainInfo.renderPassDescriptor = renderPassDescriptor;
+ }
+ else
+ {
+ swapChain->releaseAndDestroyLater();
+ m_swapChains.remove(surface);
+ return nullptr;
+ }
+ }
+ return &swapChainInfo;
+}
+
QRhiCommandBuffer *SubmissionContext::currentFrameCommandBuffer() const
{
return m_currentSwapChain->currentFrameCommandBuffer();
@@ -1286,6 +1274,11 @@ QRhiRenderTarget *SubmissionContext::currentFrameRenderTarget() const
return m_currentSwapChain->currentFrameRenderTarget();
}
+QRhiSwapChain *SubmissionContext::currentSwapChain() const
+{
+ return m_currentSwapChain;
+}
+
QRhiRenderPassDescriptor *SubmissionContext::currentRenderPassDescriptor() const
{
return m_currentRenderPassDescriptor;
@@ -1305,8 +1298,8 @@ QSurfaceFormat SubmissionContext::format() const noexcept
// than the other way around
bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
{
- static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight.irradiance"));
- static const int specularId = StringToInt::lookupId(QLatin1String("envLight.specular"));
+ static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight_irradiance"));
+ static const int specularId = StringToInt::lookupId(QLatin1String("envLight_specular"));
// Activate textures and update TextureUniform in the pack
// with the correct textureUnit
@@ -1600,6 +1593,101 @@ void SubmissionContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTargetId,
//* }
}
+namespace
+{
+template<std::size_t N>
+constexpr int getFirstAvailableBit(const std::bitset<N>& bits)
+{
+ for (std::size_t i = 0; i < N; i++)
+ {
+ if (!bits.test(i))
+ return i;
+ }
+ return -1;
+}
+// This function ensures that the shader stages all have the same bindings
+void preprocessRHIShader(QVector<QByteArray>& shaderCodes)
+{
+ // Map the variable names to bindings
+ std::map<QByteArray, int> bindings;
+ bindings["qt3d_render_view_uniforms"] = 0;
+ bindings["qt3d_command_uniforms"] = 1;
+ std::bitset<512> assignedBindings;
+ assignedBindings.set(0);
+ assignedBindings.set(1);
+
+ thread_local const QRegularExpression samplerRegex(
+ QStringLiteral("binding\\s*=\\s*([0-9]+).*\\)\\s*uniform\\s*[ui]?sampler[a-zA-Z0-9]+\\s*([a-zA-Z0-9_]+)\\s*;"));
+ thread_local const QRegularExpression uboRegex(
+ QStringLiteral("(?:std140\\s*,\\s*binding\\s*=\\s*([0-9]+).*|binding\\s*=\\s*([0-9]+)\\s*,\\s*std140.*)\\)\\s*uniform\\s*([a-zA-Z0-9_]+)"));
+
+ auto replaceBinding = [&bindings, &assignedBindings] (int& offset, QRegularExpressionMatch& match, QByteArray& code, int indexCapture, int variableCapture) noexcept
+ {
+ int index = match.captured(indexCapture).toInt();
+ QByteArray variable = match.captured(variableCapture).toUtf8();
+
+ auto it = bindings.find(variable);
+ if (it == bindings.end())
+ {
+ // 1. Check if the index is already used
+ if (assignedBindings.test(index))
+ {
+ index = getFirstAvailableBit(assignedBindings);
+ if (index == -1) {
+ return;
+ }
+
+ const int indexStartOffset = match.capturedStart(indexCapture);
+ const int indexEndOffset = match.capturedEnd(indexCapture);
+ const int indexLength = indexEndOffset - indexStartOffset;
+ code.replace(indexStartOffset, indexLength, QByteArray::number(index));
+ }
+
+ assignedBindings.set(index);
+ bindings.emplace(std::move(variable), index);
+ }
+ else
+ {
+ int indexToUse = it->second;
+ const int indexStartOffset = match.capturedStart(indexCapture);
+ const int indexEndOffset = match.capturedEnd(indexCapture);
+ const int indexLength = indexEndOffset - indexStartOffset;
+ code.replace(indexStartOffset, indexLength, QByteArray::number(indexToUse));
+ }
+ // This may fail in the case where the replaced offset is an incredibly long number,
+ // which seems quite unlikely
+ offset = match.capturedEnd(0);
+ };
+
+ for (QByteArray& shaderCode : shaderCodes)
+ {
+ // Regex for the sampler variables
+ int offset = 0;
+ auto match = samplerRegex.match(shaderCode, offset);
+ while (match.hasMatch())
+ {
+ const int indexCapture = 1;
+ const int variableCapture = 2;
+ replaceBinding(offset, match, shaderCode, indexCapture, variableCapture);
+
+ match = samplerRegex.match(shaderCode, offset);
+ }
+
+ // Regex for the UBOs
+ offset = 0;
+ match = uboRegex.match(shaderCode, offset);
+ while (match.hasMatch())
+ {
+ const int indexCapture = !match.capturedView(1).isEmpty() ? 1 : 2;
+ const int variableCapture = 3;
+ replaceBinding(offset, match, shaderCode, indexCapture, variableCapture);
+
+ match = uboRegex.match(shaderCode, offset);
+ }
+ }
+}
+}
+
// Called by GL Command Thread
SubmissionContext::ShaderCreationInfo SubmissionContext::createShaderProgram(RHIShader *shader)
{
@@ -1665,7 +1753,8 @@ SubmissionContext::ShaderCreationInfo SubmissionContext::createShaderProgram(RHI
}
// Perform shader introspection
- shader->introspect();
+ if (success)
+ shader->introspect();
return {success, logs};
}
@@ -1690,7 +1779,10 @@ void SubmissionContext::loadShader(Shader *shaderNode,
const QVector<Qt3DCore::QNodeId> sharedShaderIds = rhiShaderManager->shaderIdsForProgram(rhiShader);
if (sharedShaderIds.size() == 1) {
// Shader in the cache hasn't been loaded yet
- rhiShader->setShaderCode(shaderNode->shaderCode());
+ QVector<QByteArray> shaderCodes = shaderNode->shaderCode();
+ preprocessRHIShader(shaderCodes);
+ rhiShader->setShaderCode(shaderCodes);
+
const ShaderCreationInfo loadResult = createShaderProgram(rhiShader);
shaderNode->setStatus(loadResult.linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error);
shaderNode->setLog(loadResult.logs);
diff --git a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext_p.h b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext_p.h
index dba99e505..6a1091e51 100644
--- a/src/plugins/renderers/rhi/graphicshelpers/submissioncontext_p.h
+++ b/src/plugins/renderers/rhi/graphicshelpers/submissioncontext_p.h
@@ -191,6 +191,17 @@ public:
StateVariant* getState(RenderStateSet *ss,
StateMask type) const;
+ // Swap chain
+
+
+ struct SwapChainInfo
+ {
+ QRhiSwapChain *swapChain = nullptr;
+ QRhiRenderBuffer *renderBuffer = nullptr;
+ QRhiRenderPassDescriptor *renderPassDescriptor = nullptr;
+ };
+ SwapChainInfo* swapChainForSurface(QSurface* surface) noexcept;
+
QRhiResourceUpdateBatch *m_currentUpdates{};
@@ -198,10 +209,10 @@ public:
QRhiCommandBuffer *currentFrameCommandBuffer() const;
QRhiRenderTarget *currentFrameRenderTarget() const;
QRhiRenderPassDescriptor *currentRenderPassDescriptor() const;
+ QRhiSwapChain *currentSwapChain() const;
QSurfaceFormat format() const noexcept;
private:
-
// Material
Material* activeMaterial() const { return m_material; }
void setActiveMaterial(Material* rmat);
@@ -223,6 +234,7 @@ private:
void applyState(const StateVariant &state,
QRhiGraphicsPipeline *graphicsPipeline);
+
bool m_ownCurrent;
const unsigned int m_id;
QSurface *m_surface;
@@ -249,22 +261,10 @@ private:
GraphicsApiFilterData m_contextInfo;
QRhi* m_rhi;
-
- struct SwapChainInfo
- {
- QRhiSwapChain *swapChain = nullptr;
- QRhiRenderBuffer *renderBuffer = nullptr;
- QRhiRenderPassDescriptor *renderPassDescriptor = nullptr;
- };
-
QHash<QSurface *, SwapChainInfo> m_swapChains;
QRhiSwapChain *m_currentSwapChain;
QRhiRenderPassDescriptor *m_currentRenderPassDescriptor;
-#if QT_CONFIG(vulkan)
- QVulkanInstance *m_vkInstance;
- bool m_ownsVkInstance{};
-#endif
#ifndef QT_NO_OPENGL
QOffscreenSurface *m_fallbackSurface;
#endif
diff --git a/src/plugins/renderers/rhi/renderer/rendercommand.cpp b/src/plugins/renderers/rhi/renderer/rendercommand.cpp
index 5d311480a..ee1b76cef 100644
--- a/src/plugins/renderers/rhi/renderer/rendercommand.cpp
+++ b/src/plugins/renderers/rhi/renderer/rendercommand.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "rendercommand_p.h"
+#include "renderer/rhigraphicspipeline_p.h"
QT_BEGIN_NAMESPACE
@@ -78,6 +79,11 @@ RenderCommand::RenderCommand()
m_workGroups[2] = 0;
}
+bool RenderCommand::isValid() const noexcept
+{
+ return m_rhiShader && pipeline && pipeline->pipeline();
+}
+
bool operator==(const RenderCommand &a, const RenderCommand &b) noexcept
{
return (a.m_rhiShader == b.m_rhiShader && a.m_material == b.m_material &&
diff --git a/src/plugins/renderers/rhi/renderer/rendercommand_p.h b/src/plugins/renderers/rhi/renderer/rendercommand_p.h
index f4031b711..0a3d03e93 100644
--- a/src/plugins/renderers/rhi/renderer/rendercommand_p.h
+++ b/src/plugins/renderers/rhi/renderer/rendercommand_p.h
@@ -97,6 +97,8 @@ class Q_AUTOTEST_EXPORT RenderCommand
public:
RenderCommand();
+ bool isValid() const noexcept;
+
HMaterial m_material; // Purely used to ease sorting (minimize stage changes, binding changes ....)
RHIShader *m_rhiShader; // GL Shader to be used at render time
Qt3DCore::QNodeId m_shaderId; // Shader for given pass and mesh
diff --git a/src/plugins/renderers/rhi/renderer/renderer.cpp b/src/plugins/renderers/rhi/renderer/renderer.cpp
index 03d72e010..34ae18b5d 100644
--- a/src/plugins/renderers/rhi/renderer/renderer.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderer.cpp
@@ -123,7 +123,6 @@
#include <QtGui/private/qopenglcontext_p.h>
#include <QGuiApplication>
-#include <QShaderBaker>
QT_BEGIN_NAMESPACE
@@ -679,15 +678,6 @@ void Renderer::render()
}
}
-QShader getShader(const QString &name)
-{
- QFile f(name);
- if (f.open(QIODevice::ReadOnly))
- return QShader::fromSerialized(f.readAll());
-
- return QShader();
-}
-
// Either called by render if Qt3D is in charge of the RenderThread
// or by QRenderAspectPrivate::renderSynchronous (for Scene3D)
void Renderer::doRender(bool swapBuffers)
@@ -728,25 +718,47 @@ void Renderer::doRender(bool swapBuffers)
QVector<RHIPassInfo> rhiPassesInfo;
if (canRender()) {
- { // Scoped to destroy surfaceLock
- QSurface *surface = nullptr;
- for (const RenderView *rv: renderViews) {
- surface = rv->surface();
- if (surface)
- break;
- }
+ QSurface *surface = nullptr;
+ for (const RenderView *rv: renderViews) {
+ surface = rv->surface();
+ if (surface)
+ break;
+ }
+
+ // In case we did not draw because e.g. there wase no swapchain,
+ // we keep the resource updates from the previous frame.
+ if (!m_submissionContext->m_currentUpdates)
+ {
+ m_submissionContext->m_currentUpdates = m_submissionContext->rhi()->nextResourceUpdateBatch();
+ }
+
+ // 1) Execute commands for buffer uploads, texture updates, shader loading first
+ updateResources();
+
+ rhiPassesInfo = prepareCommandsSubmission(renderViews);
+ // 2) Update Pipelines and copy data into commands to allow concurrent submission
+ preprocessingComplete = true;
+
+ bool hasCommands = false;
+ for (const RenderView *rv: renderViews) {
+ const auto& commands = rv->commands();
+ hasCommands = std::any_of(
+ commands.begin(),
+ commands.end(),
+ [] (const RenderCommand& cmd) {
+ return cmd.isValid();
+ });
+ if (hasCommands)
+ break;
+ }
+ if (hasCommands) {
+ // Scoped to destroy surfaceLock
SurfaceLocker surfaceLock(surface);
const bool surfaceIsValid = (surface && surfaceLock.isSurfaceValid());
if (surfaceIsValid) {
beganDrawing = m_submissionContext->beginDrawing(surface);
if (beganDrawing) {
- // 1) Execute commands for buffer uploads, texture updates, shader loading first
- updateResources();
- // 2) Update Pipelines and copy data into commands to allow concurrent submission
- rhiPassesInfo = prepareCommandsSubmission(renderViews);
- preprocessingComplete = true;
-
// Purge shader which aren't used any longer
static int callCount = 0;
++callCount;
@@ -764,7 +776,7 @@ void Renderer::doRender(bool swapBuffers)
// Only try to submit the RenderViews if the preprocessing was successful
// This part of the submission is happening in parallel to the RV building for the next frame
- if (preprocessingComplete) {
+ if (beganDrawing) {
submissionStatsPart1.end(submissionStatsPart2.restart());
// 3) Submit the render commands for frame n (making sure we never reference something that could be changing)
@@ -900,7 +912,10 @@ QSurfaceFormat Renderer::format()
void Renderer::updateGraphicsPipeline(RenderCommand& cmd, RenderView *rv, int renderViewIndex)
{
if (!cmd.m_rhiShader)
+ {
+ qDebug() << "Warning: command has no shader";
return;
+ }
// The Graphics Pipeline defines
// - Render State (Depth, Culling, Stencil, Blending)
@@ -934,7 +949,6 @@ void Renderer::updateGraphicsPipeline(RenderCommand& cmd, RenderView *rv, int re
if (!graphicsPipeline) {
qDebug() << "Warning : could not create a graphics pipeline";
- RHIGraphicsPipeline *graphicsPipeline = m_RHIResourceManagers->rhiGraphicsPipelineManager()->getOrCreateResource(pipelineKey);
return;
}
@@ -951,6 +965,11 @@ void Renderer::updateGraphicsPipeline(RenderCommand& cmd, RenderView *rv, int re
if (graphicsPipeline->pipeline() == nullptr || requiredRebuild) {
bool ok = true;
+ const SubmissionContext::SwapChainInfo* swapchain =
+ m_submissionContext->swapChainForSurface(rv->surface());
+ if (!swapchain || !swapchain->swapChain || !swapchain->renderPassDescriptor)
+ return;
+
// TO DO: Find a way to recycle those
// Create Per Command UBO
QRhiBuffer *commandUBO = m_submissionContext->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, sizeof(CommandUBO));
@@ -1124,11 +1143,12 @@ void Renderer::updateGraphicsPipeline(RenderCommand& cmd, RenderView *rv, int re
inputBindings.resize(uniqueBindings.size());
for (int i = 0, m = uniqueBindings.size(); i < m; ++i) {
const BufferBinding binding = uniqueBindings.at(i);
+ /*
qDebug() << binding.bufferId
<< binding.stride
<< binding.classification
<< binding.attributeDivisor;
-
+ */
inputBindings[i] = QRhiVertexInputBinding{binding.stride, binding.classification, int(binding.attributeDivisor) };
}
@@ -1138,14 +1158,15 @@ void Renderer::updateGraphicsPipeline(RenderCommand& cmd, RenderView *rv, int re
pipeline->setVertexInputLayout(inputLayout);
pipeline->setShaderResourceBindings(shaderResourceBindings);
- pipeline->setRenderPassDescriptor(m_submissionContext->currentRenderPassDescriptor());
- graphicsPipeline->setAttributesToBindingHash(attributeNameToBinding);
+ pipeline->setRenderPassDescriptor(swapchain->renderPassDescriptor);
+ graphicsPipeline->setAttributesToBindingHash(attributeNameToBinding);
// Render States
m_submissionContext->applyStateSet(renderState, pipeline);
+
ok = pipeline->build();
assert(ok);
}
@@ -1201,7 +1222,10 @@ QVector<Renderer::RHIPassInfo> Renderer::prepareCommandsSubmission(const QVector
// By this time shaders should have been loaded
RHIShader *shader = m_RHIResourceManagers->rhiShaderManager()->lookupResource(command.m_shaderId);
if (!shader)
+ {
+ qDebug() << "Warning: could not find shader";
continue;
+ }
// We should never have inserted a command for which these are null
// in the first place
@@ -1497,7 +1521,6 @@ void Renderer::updateResources()
{
const QVector<HTexture> activeTextureHandles = std::move(m_dirtyTextures);
for (const HTexture &handle: activeTextureHandles) {
- RHI_UNIMPLEMENTED;
Texture *texture = m_nodesManager->textureManager()->data(handle);
// Can be null when using Scene3D rendering
diff --git a/src/plugins/renderers/rhi/renderer/renderview.cpp b/src/plugins/renderers/rhi/renderer/renderview.cpp
index 49a7c2d9e..70020093a 100644
--- a/src/plugins/renderers/rhi/renderer/renderview.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderview.cpp
@@ -1157,19 +1157,45 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
// Environment Light
int envLightCount = 0;
if (environmentLight && environmentLight->isEnabled()) {
+ static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight_irradiance"));
+ static const int specularId = StringToInt::lookupId(QLatin1String("envLight_specular"));
ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData());
if (shaderData) {
- setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight"));
+ //setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight"));
envLightCount = 1;
+
+ // ("specularSize", "irradiance", "irradianceSize", "specular")
+ auto irr = shaderData->properties()["irradiance"].value.value<Qt3DCore::QNodeId>();
+ auto spec = shaderData->properties()["specular"].value.value<Qt3DCore::QNodeId>();
+
+ setUniformValue(command->m_parameterPack, irradianceId, irr);
+ setUniformValue(command->m_parameterPack, specularId, spec);
}
- } else {
- // with some drivers, samplers (like the envbox sampler) need to be bound even though
- // they may not be actually used, otherwise draw calls can fail
- static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight_irradiance"));
- static const int specularId = StringToInt::lookupId(QLatin1String("envLight_specular"));
-// setUniformValue(command->m_parameterPack, irradianceId, m_renderer->submissionContext()->maxTextureUnitsCount());
-// setUniformValue(command->m_parameterPack, specularId, m_renderer->submissionContext()->maxTextureUnitsCount());
}
+ //if (environmentLight && environmentLight->isEnabled()) {
+ // ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData());
+ // if (shaderData) {
+ // setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight"));
+ // envLightCount = 1;
+ // }
+ //} else {
+ // // with some drivers, samplers (like the envbox sampler) need to be bound even though
+ // // they may not be actually used, otherwise draw calls can fail
+ // static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight_irradiance"));
+ // static const int specularId = StringToInt::lookupId(QLatin1String("envLight_specular"));
+ //
+ // // for (const auto& sampler : shader->samplers())
+ // // {
+ // // if (sampler.m_nameId == irradianceId)
+ // // {
+ // // setUniformValue(command->m_parameterPack, irradianceId, sampler.m_location);
+ // // }
+ // // else if (sampler.m_nameId == specularId)
+ // // {
+ // // setUniformValue(command->m_parameterPack, specularId, sampler.m_location);
+ // // }
+ // // }
+ //}
setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount);
}
}
diff --git a/src/plugins/renderers/rhi/renderer/renderview_p.h b/src/plugins/renderers/rhi/renderer/renderview_p.h
index c770eaaec..cceefe5e4 100644
--- a/src/plugins/renderers/rhi/renderer/renderview_p.h
+++ b/src/plugins/renderers/rhi/renderer/renderview_p.h
@@ -133,13 +133,13 @@ struct RenderViewUBO
float viewportMatrix[16];
float inverseViewportMatrix[16];
float textureTransformMatrix[4];
- float eyePosition[3]; float pad1;
- float aspectRatio; float pad2[3];
- float gamma; float pad3[3];
- float exposure; float pad4[3];
- float time; float pad5[3];
+ float eyePosition[3];
+ float aspectRatio;
+ float gamma;
+ float exposure;
+ float time;
};
-static_assert(sizeof(RenderViewUBO) == sizeof(float) * (8 * 16 + 6 * 4), "UBO doesn't match std140");
+static_assert(sizeof(RenderViewUBO) == sizeof(float) * (8 * 16 + 1 * 4 + 1 * 3 + 4 * 1), "UBO doesn't match std140");
class Q_AUTOTEST_EXPORT RenderView
{
diff --git a/src/plugins/renderers/rhi/textures/texture.cpp b/src/plugins/renderers/rhi/textures/texture.cpp
index 47a2d8025..c1a1bc19b 100644
--- a/src/plugins/renderers/rhi/textures/texture.cpp
+++ b/src/plugins/renderers/rhi/textures/texture.cpp
@@ -113,6 +113,7 @@ QRhiTexture::Format rhiFormatFromTextureFormat(QAbstractTexture::TextureFormat f
case QAbstractTexture::RGBA8_ETC2_EAC:
return QRhiTexture::ETC2_RGBA8;
default:
+ Q_UNREACHABLE();
return QRhiTexture::UnknownFormat;
}
}
@@ -145,6 +146,7 @@ QRhiSampler::Filter rhiMipMapFilterFromTextureFilter(QAbstractTexture::Filter fi
case QAbstractTexture::LinearMipMapLinear:
return QRhiSampler::Linear;
default:
+ Q_UNREACHABLE();
return QRhiSampler::None;
}
}
@@ -165,6 +167,8 @@ rhiWrapModeFromTextureWrapMode(QTextureWrapMode::WrapMode x,
return QRhiSampler::ClampToEdge;
case Qt3DRender::QTextureWrapMode::MirroredRepeat:
return QRhiSampler::Mirror;
+ default:
+ Q_UNREACHABLE();
}
};
@@ -197,19 +201,23 @@ QRhiSampler::CompareOp rhiCompareOpFromTextureCompareOp(QAbstractTexture::Compar
// This uploadGLData where the data is a fullsize subimage
// as QOpenGLTexture doesn't allow partial subimage uploads
-QRhiTextureUploadEntry uploadRhiData(int level, int layer, QOpenGLTexture::CubeMapFace face,
+QRhiTextureUploadEntry uploadRhiData(int level, int layer,
const QByteArray &bytes, const QTextureImageDataPtr &data) noexcept
{
+ qDebug() << "Case 1: " << level << layer ;
QRhiTextureSubresourceUploadDescription description;
description.setData(bytes);
+ description.setSourceSize({data->width(), data->height()});
+
return QRhiTextureUploadEntry(layer, level, description);
}
// For partial sub image uploads
-QRhiTextureUploadEntry uploadRhiData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+QRhiTextureUploadEntry uploadRhiData(int mipLevel, int layer,
int xOffset, int yOffset, int zOffset,
const QByteArray &bytes, const QTextureImageDataPtr &data) noexcept
{
+ qDebug() << "Case 2: " << mipLevel << layer << xOffset << yOffset << zOffset;
QRhiTextureSubresourceUploadDescription description;
description.setData(bytes);
description.setSourceTopLeft(QPoint(xOffset, yOffset));
@@ -580,14 +588,6 @@ QRhiTexture *RHITexture::buildRhiTexture(SubmissionContext *ctx)
if (issRGB8Format)
rhiFlags |= QRhiTexture::sRGB;
-// // Set layers count if texture array
-// if (actualTarget == QAbstractTexture::Target1DArray ||
-// actualTarget == QAbstractTexture::Target2DArray ||
-// actualTarget == QAbstractTexture::Target2DMultisampleArray ||
-// actualTarget == QAbstractTexture::TargetCubeMapArray) {
-// glTex->setLayers(m_properties.layers);
-// }
-
if (actualTarget == QAbstractTexture::Target2DMultisample ||
actualTarget == QAbstractTexture::Target2DMultisampleArray) {
// Set samples count if multisampled texture
@@ -616,24 +616,75 @@ void RHITexture::uploadRhiTextureData(SubmissionContext *ctx)
if (m_textureData) {
const QVector<QTextureImageDataPtr> imgData = m_textureData->imageData();
- for (const QTextureImageDataPtr &data : imgData) {
- const int mipLevels = m_properties.generateMipMaps ? 1 : data->mipLevels();
+ if (m_properties.samples == 1)
+ {
+ for (const QTextureImageDataPtr &data : imgData) {
+ const int mipLevels = m_properties.generateMipMaps ? 1 : data->mipLevels();
+ Q_ASSERT(mipLevels <= ctx->rhi()->mipLevelsForSize({data->width(), data->height()}));
- for (int layer = 0; layer < data->layers(); layer++) {
- for (int face = 0; face < data->faces(); face++) {
+ const int maxLevels = (data->layers() == 1 && data->faces() == 1) ? 1
+ : (data->layers() > 1 && data->faces() == 1) ? data->layers()
+ : (data->faces() > 1 && data->layers() == 1) ? data->faces()
+ : 0;
+
+ if (data->layers() == 1 && data->faces() == 1)
+ {
for (int level = 0; level < mipLevels; level++) {
// ensure we don't accidentally cause a detach / copy of the raw bytes
- const QByteArray bytes(data->data(layer, face, level));
- const QRhiTextureUploadEntry entry = uploadRhiData(level, layer,
- static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face),
- bytes, data);
+ const QByteArray bytes(data->data(0, 0, level));
+ const QRhiTextureUploadEntry entry = uploadRhiData(level, 0, bytes, data);
uploadEntries.push_back(entry);
}
}
+ else if (data->layers() > 1 && data->faces() == 1)
+ {
+ for (int layer = 0; layer < data->layers(); layer++) {
+ for (int level = 0; level < mipLevels; level++) {
+ // ensure we don't accidentally cause a detach / copy of the raw bytes
+ const QByteArray bytes(data->data(layer, 0, level));
+ const QRhiTextureUploadEntry entry = uploadRhiData(level, layer, bytes, data);
+ uploadEntries.push_back(entry);
+ }
+ }
+ }
+ else if (data->faces() > 1 && data->layers() == 1)
+ {
+ for (int face = 0; face < data->faces(); face++) {
+ for (int level = 0; level < mipLevels; level++) {
+ // ensure we don't accidentally cause a detach / copy of the raw bytes
+ const QByteArray bytes(data->data(0, face, level));
+ const QRhiTextureUploadEntry entry = uploadRhiData(level, face, bytes, data);
+ uploadEntries.push_back(entry);
+ }
+ }
+ }
+ else
+ {
+ qDebug() << "Unsupported case";
+ }
}
}
- }
+ else
+ {
+ for (const QTextureImageDataPtr &data : imgData) {
+ const int mipLevels = m_properties.generateMipMaps ? 1 : data->mipLevels();
+
+ for (int layer = 0; layer < data->layers(); layer++) {
+ for (int face = 0; face < data->faces(); face++) {
+ for (int level = 0; level < mipLevels; level++) {
+ // ensure we don't accidentally cause a detach / copy of the raw bytes
+ const QByteArray bytes(data->data(layer, face, level));
+ const QRhiTextureUploadEntry entry = uploadRhiData(level, layer,
+ bytes, data);
+ uploadEntries.push_back(entry);
+ }
+ }
+ }
+ }
+ }
+ }
+/*
// Upload all QTexImageData references by the TextureImages
for (int i = 0; i < std::min(m_images.size(), m_imageData.size()); i++) {
const QTextureImageDataPtr &imgData = m_imageData.at(i);
@@ -686,7 +737,7 @@ void RHITexture::uploadRhiTextureData(SubmissionContext *ctx)
bytes, imgData);
uploadEntries.push_back(entry);
}
-
+*/
QRhiTextureUploadDescription uploadDescription;
uploadDescription.setEntries(uploadEntries.begin(), uploadEntries.end());
diff --git a/src/render/render.pro b/src/render/render.pro
index 528546230..ef5b154ff 100644
--- a/src/render/render.pro
+++ b/src/render/render.pro
@@ -19,6 +19,7 @@ include (raycasting/raycasting.pri)
include (services/services.pri)
include (shadergraph/shadergraph.pri)
include (texture/texture.pri)
+include (surfaces/surfaces.pri)
gcov {
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
diff --git a/src/render/shadergraph/qshadergenerator.cpp b/src/render/shadergraph/qshadergenerator.cpp
index 15178fc71..92c69be72 100644
--- a/src/render/shadergraph/qshadergenerator.cpp
+++ b/src/render/shadergraph/qshadergenerator.cpp
@@ -473,7 +473,7 @@ namespace
int currentInputLocation { 0 };
int currentOutputLocation { 0 };
- int currentBinding { 0 };
+ int currentBinding { 2 };
QByteArrayList ubo;
};
diff --git a/src/render/surfaces/surfaces.pri b/src/render/surfaces/surfaces.pri
new file mode 100644
index 000000000..0d25a36c6
--- /dev/null
+++ b/src/render/surfaces/surfaces.pri
@@ -0,0 +1,9 @@
+INCLUDEPATH += $$PWD
+
+qtConfig(vulkan) {
+HEADERS += \
+ $$PWD/vulkaninstance_p.h \
+
+SOURCES += \
+ $$PWD/vulkaninstance.cpp
+}
diff --git a/src/render/surfaces/vulkaninstance.cpp b/src/render/surfaces/vulkaninstance.cpp
new file mode 100644
index 000000000..adbeb3074
--- /dev/null
+++ b/src/render/surfaces/vulkaninstance.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "vulkaninstance_p.h"
+#include <QVulkanInstance>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QVulkanInstance &staticVulkanInstance() noexcept
+{
+ static QVulkanInstance* vkInstance = []
+ {
+ QVulkanInstance* v = new QVulkanInstance;
+#ifndef Q_OS_ANDROID
+ v->setLayers({ "VK_LAYER_LUNARG_standard_validation" });
+#else
+ v->setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+
+ if (!v->create()) {
+ qWarning("Failed to create Vulkan instance");
+ }
+ return v;
+ }();
+ return *vkInstance;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/surfaces/vulkaninstance_p.h b/src/render/surfaces/vulkaninstance_p.h
new file mode 100644
index 000000000..ca6e2124f
--- /dev/null
+++ b/src/render/surfaces/vulkaninstance_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_VULKANINSTANCE_P_H
+#define QT3DRENDER_VULKANINSTANCE_P_H
+
+#include <Qt3DRender/private/qt3drender_global_p.h>
+QT_BEGIN_NAMESPACE
+#if QT_CONFIG(vulkan)
+class QVulkanInstance;
+namespace Qt3DRender {
+Q_3DRENDERSHARED_PRIVATE_EXPORT
+QVulkanInstance& staticVulkanInstance() noexcept;
+} // Qt3DRender
+#endif
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_VULKANINSTANCE_P_H