summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp')
-rw-r--r--src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp784
1 files changed, 784 insertions, 0 deletions
diff --git a/src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp b/src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp
new file mode 100644
index 00000000..d78c51d9
--- /dev/null
+++ b/src/Runtime/Source/render/backends/gl/Qt3DSRenderBackendGL3.cpp
@@ -0,0 +1,784 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "render/backends/gl/Qt3DSRenderBackendGL3.h"
+#include "render/backends/gl/Qt3DSRenderBackendInputAssemblerGL.h"
+#include "render/backends/gl/Qt3DSRenderBackendRenderStatesGL.h"
+#include "render/backends/gl/Qt3DSRenderBackendShaderProgramGL.h"
+
+#ifdef RENDER_BACKEND_LOG_GL_ERRORS
+#define RENDER_LOG_ERROR_PARAMS(x) checkGLError(#x, __FILE__, __LINE__)
+#else
+#define RENDER_LOG_ERROR_PARAMS(x) checkGLError()
+#endif
+
+#define GL_CALL_EXTRA_FUNCTION(x) m_glExtraFunctions->x; RENDER_LOG_ERROR_PARAMS(x);
+
+#if defined(QT_OPENGL_ES)
+#define GL_CALL_TIMER_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x);
+#define GL_CALL_TESSELATION_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x);
+#else
+#define GL_CALL_TIMER_EXT(x) m_timerExtension->x; RENDER_LOG_ERROR_PARAMS(x);
+#define GL_CALL_TESSELATION_EXT(x) m_tessellationShader->x; RENDER_LOG_ERROR_PARAMS(x);
+#define GL_CALL_MULTISAMPLE_EXT(x) m_multiSample->x; RENDER_LOG_ERROR_PARAMS(x);
+#endif
+
+namespace qt3ds {
+namespace render {
+
+#ifndef GL_PATCH_VERTICES
+#define GL_PATCH_VERTICES 0x8E72
+#endif
+
+ /// constructor
+ NVRenderBackendGL3Impl::NVRenderBackendGL3Impl(NVFoundationBase &fnd,
+ qt3ds::foundation::IStringTable &stringTable,
+ const QSurfaceFormat &format)
+ : NVRenderBackendGLBase(fnd, stringTable, format)
+ {
+ eastl::string exts3tc("GL_EXT_texture_compression_s3tc");
+ eastl::string extsdxt("GL_EXT_texture_compression_dxt1");
+ eastl::string extsAniso("GL_EXT_texture_filter_anisotropic");
+ eastl::string extsTexSwizzle("GL_ARB_texture_swizzle");
+ eastl::string extsAstcHDR("GL_KHR_texture_compression_astc_hdr");
+ eastl::string extsAstcLDR("GL_KHR_texture_compression_astc_ldr");
+ eastl::string extsFPRenderTarget("GL_EXT_color_buffer_float");
+ eastl::string extsTimerQuery("GL_EXT_timer_query");
+ eastl::string extsGpuShader5("EXT_gpu_shader5");
+
+ const char *languageVersion = GetShadingLanguageVersion();
+ qCInfo(TRACE_INFO, "GLSL version: %s", languageVersion);
+
+ eastl::string apiVersion(getVersionString());
+ qCInfo(TRACE_INFO, "GL version: %s", apiVersion.c_str());
+
+ eastl::string apiVendor(getVendorString());
+ qCInfo(TRACE_INFO, "HW vendor: %s", apiVendor.c_str());
+
+ eastl::string apiRenderer(getRendererString());
+ qCInfo(TRACE_INFO, "Vendor renderer: %s", apiRenderer.c_str());
+
+ // clear support bits
+ m_backendSupport.caps.u32Values = 0;
+
+ // get extension count
+ GLint numExtensions = 0;
+ GL_CALL_EXTRA_FUNCTION(glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions));
+
+ eastl::string extensionBuffer;
+
+ for (QT3DSI32 i = 0; i < numExtensions; i++) {
+ char *extensionString = (char *)GL_CALL_EXTRA_FUNCTION(glGetStringi(GL_EXTENSIONS, i));
+
+ m_extensions.push_back(QString::fromLocal8Bit(extensionString));
+
+ if (extensionBuffer.size())
+ extensionBuffer.append(" ");
+ extensionBuffer.append(extensionString);
+
+ // search for extension
+ if (!m_backendSupport.caps.bits.bDXTImagesSupported
+ && (exts3tc.compare(extensionString) == 0 || extsdxt.compare(extensionString) == 0)) {
+ m_backendSupport.caps.bits.bDXTImagesSupported = true;
+ } else if (!m_backendSupport.caps.bits.bAnistropySupported
+ && extsAniso.compare(extensionString) == 0) {
+ m_backendSupport.caps.bits.bAnistropySupported = true;
+ } else if (!m_backendSupport.caps.bits.bFPRenderTargetsSupported
+ && extsFPRenderTarget.compare(extensionString) == 0) {
+ m_backendSupport.caps.bits.bFPRenderTargetsSupported = true;
+ } else if (!m_backendSupport.caps.bits.bTimerQuerySupported
+ && extsTimerQuery.compare(extensionString) == 0) {
+ m_backendSupport.caps.bits.bTimerQuerySupported = true;
+ } else if (!m_backendSupport.caps.bits.bGPUShader5ExtensionSupported
+ && extsGpuShader5.compare(extensionString) == 0) {
+ m_backendSupport.caps.bits.bGPUShader5ExtensionSupported = true;
+ }
+
+ }
+
+ qCInfo(TRACE_INFO, "OpenGL extensions: %s", extensionBuffer.c_str());
+
+ // texture swizzle is always true
+ m_backendSupport.caps.bits.bTextureSwizzleSupported = true;
+ // depthstencil renderbuffer support is always true
+ m_backendSupport.caps.bits.bDepthStencilSupported = true;
+ // constant buffers support is always true
+ m_backendSupport.caps.bits.bConstantBufferSupported = true;
+ m_backendSupport.caps.bits.bStandardDerivativesSupported = true;
+ m_backendSupport.caps.bits.bVertexArrayObjectSupported = true;
+ m_backendSupport.caps.bits.bTextureLodSupported = true;
+
+ if (!isESCompatible()) {
+ // render to float textures is always supported on none ES systems which support >=GL3
+ m_backendSupport.caps.bits.bFPRenderTargetsSupported = true;
+ // multisampled texture is always supported on none ES systems which support >=GL3
+ m_backendSupport.caps.bits.bMsTextureSupported = true;
+ // timer queries are always supported on none ES systems which support >=GL3
+ m_backendSupport.caps.bits.bTimerQuerySupported = true;
+ }
+
+ // query hardware
+ GL_CALL_EXTRA_FUNCTION(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &m_MaxAttribCount));
+
+ // internal state tracker
+ m_pCurrentMiscState = QT3DS_NEW(m_Foundation.getAllocator(), NVRenderBackendMiscStateGL)();
+
+ // finally setup caps based on device
+ setAndInspectHardwareCaps();
+
+ // Initialize extensions
+#if defined(QT_OPENGL_ES_2)
+ m_qt3dsExtensions = new Qt3DSOpenGLES2Extensions;
+ m_qt3dsExtensions->initializeOpenGLFunctions();
+#else
+ m_timerExtension = new QOpenGLExtension_ARB_timer_query;
+ m_timerExtension->initializeOpenGLFunctions();
+ m_tessellationShader = new QOpenGLExtension_ARB_tessellation_shader;
+ m_tessellationShader->initializeOpenGLFunctions();
+ m_multiSample = new QOpenGLExtension_ARB_texture_multisample;
+ m_multiSample->initializeOpenGLFunctions();
+ m_qt3dsExtensions = new Qt3DSOpenGLExtensions;
+ m_qt3dsExtensions->initializeOpenGLFunctions();
+#endif
+ }
+ /// destructor
+ NVRenderBackendGL3Impl::~NVRenderBackendGL3Impl()
+ {
+ if (m_pCurrentMiscState)
+ NVDelete(m_Foundation.getAllocator(), m_pCurrentMiscState);
+#if !defined(QT_OPENGL_ES_2)
+ if (m_timerExtension)
+ delete m_timerExtension;
+ if (m_tessellationShader)
+ delete m_tessellationShader;
+ if (m_multiSample)
+ delete m_multiSample;
+#endif
+ if (m_qt3dsExtensions)
+ delete m_qt3dsExtensions;
+ }
+
+ void NVRenderBackendGL3Impl::SetMultisampledTextureData2D(
+ NVRenderBackendTextureObject to, NVRenderTextureTargetType::Enum target, size_t samples,
+ NVRenderTextureFormats::Enum internalFormat, size_t width, size_t height,
+ bool fixedsamplelocations)
+ {
+// Not supported by ES 3 yet
+#if defined(QT_OPENGL_ES)
+ NVRENDER_BACKEND_UNUSED(to);
+ NVRENDER_BACKEND_UNUSED(target);
+ NVRENDER_BACKEND_UNUSED(samples);
+ NVRENDER_BACKEND_UNUSED(internalFormat);
+ NVRENDER_BACKEND_UNUSED(width);
+ NVRENDER_BACKEND_UNUSED(height);
+ NVRENDER_BACKEND_UNUSED(fixedsamplelocations);
+#else
+ GLuint texID = HandleToID_cast(GLuint, size_t, to);
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+ GL_CALL_EXTRA_FUNCTION(glActiveTexture(GL_TEXTURE0));
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
+
+ NVRenderTextureSwizzleMode::Enum swizzleMode = NVRenderTextureSwizzleMode::NoSwizzle;
+ internalFormat = m_Conversion.replaceDeprecatedTextureFormat(GetRenderContextType(),
+ internalFormat, swizzleMode);
+
+ GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
+
+ if (NVRenderTextureFormats::isUncompressedTextureFormat(internalFormat))
+ GLConversion::fromUncompressedTextureFormatToGL(GetRenderContextType(), internalFormat,
+ glformat, gltype, glInternalFormat);
+ else if (NVRenderTextureFormats::isDepthTextureFormat(internalFormat))
+ m_Conversion.fromDepthTextureFormatToGL(GetRenderContextType(), internalFormat,
+ glformat, gltype, glInternalFormat);
+
+ GL_CALL_MULTISAMPLE_EXT(glTexImage2DMultisample(glTarget, (GLsizei)samples, glInternalFormat,
+ (GLsizei)width, (GLsizei)height, fixedsamplelocations));
+
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
+#endif
+ }
+
+ void NVRenderBackendGL3Impl::SetTextureData3D(
+ NVRenderBackendTextureObject to, NVRenderTextureTargetType::Enum target, QT3DSU32 level,
+ NVRenderTextureFormats::Enum internalFormat, size_t width, size_t height, size_t depth,
+ QT3DSI32 border, NVRenderTextureFormats::Enum format, const void *hostPtr)
+ {
+ GLuint texID = HandleToID_cast(GLuint, size_t, to);
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+ GL_CALL_EXTRA_FUNCTION(glActiveTexture(GL_TEXTURE0));
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
+ bool conversionRequired = format != internalFormat;
+
+ NVRenderTextureSwizzleMode::Enum swizzleMode = NVRenderTextureSwizzleMode::NoSwizzle;
+ internalFormat = m_Conversion.replaceDeprecatedTextureFormat(GetRenderContextType(),
+ internalFormat, swizzleMode);
+
+ GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
+
+ if (NVRenderTextureFormats::isUncompressedTextureFormat(internalFormat))
+ m_Conversion.fromUncompressedTextureFormatToGL(GetRenderContextType(), internalFormat,
+ glformat, gltype, glInternalFormat);
+
+ if (conversionRequired) {
+ GLenum dummy;
+ m_Conversion.fromUncompressedTextureFormatToGL(GetRenderContextType(), format, glformat,
+ gltype, dummy);
+ } else if (NVRenderTextureFormats::isCompressedTextureFormat(internalFormat)) {
+ m_Conversion.fromUncompressedTextureFormatToGL(GetRenderContextType(), format, glformat,
+ gltype, glInternalFormat);
+ glInternalFormat = m_Conversion.fromCompressedTextureFormatToGL(internalFormat);
+ } else if (NVRenderTextureFormats::isDepthTextureFormat(format))
+ m_Conversion.fromDepthTextureFormatToGL(GetRenderContextType(), format, glformat,
+ gltype, glInternalFormat);
+
+ GL_CALL_EXTRA_FUNCTION(glTexImage3D(glTarget, level, glInternalFormat, (GLsizei)width, (GLsizei)height,
+ (GLsizei)depth, border, glformat, gltype, hostPtr));
+
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
+ }
+
+ void NVRenderBackendGL3Impl::UpdateSampler(
+ NVRenderBackendSamplerObject /* so */, NVRenderTextureTargetType::Enum target,
+ NVRenderTextureMinifyingOp::Enum minFilter, NVRenderTextureMagnifyingOp::Enum magFilter,
+ NVRenderTextureCoordOp::Enum wrapS, NVRenderTextureCoordOp::Enum wrapT,
+ NVRenderTextureCoordOp::Enum wrapR, QT3DSF32 minLod, QT3DSF32 maxLod, QT3DSF32 lodBias,
+ NVRenderTextureCompareMode::Enum compareMode, NVRenderTextureCompareOp::Enum compareFunc,
+ QT3DSF32 anisotropy, QT3DSF32 *borderColor)
+ {
+
+ // Satisfy the compiler
+ // These are not available in GLES 3 and we don't use them right now
+ QT3DS_ASSERT(lodBias == 0.0);
+ QT3DS_ASSERT(!borderColor);
+ NVRENDER_BACKEND_UNUSED(lodBias);
+ NVRENDER_BACKEND_UNUSED(borderColor);
+
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MIN_FILTER,
+ m_Conversion.fromTextureMinifyingOpToGL(minFilter)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MAG_FILTER,
+ m_Conversion.fromTextureMagnifyingOpToGL(magFilter)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_S,
+ m_Conversion.fromTextureCoordOpToGL(wrapS)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_T,
+ m_Conversion.fromTextureCoordOpToGL(wrapT)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_R,
+ m_Conversion.fromTextureCoordOpToGL(wrapR)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MIN_LOD, minLod));
+ GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MAX_LOD, maxLod));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_COMPARE_MODE,
+ m_Conversion.fromTextureCompareModeToGL(compareMode)));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_COMPARE_FUNC,
+ m_Conversion.fromTextureCompareFuncToGL(compareFunc)));
+
+ if (m_backendSupport.caps.bits.bAnistropySupported) {
+ GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy));
+ }
+ }
+
+ void NVRenderBackendGL3Impl::UpdateTextureObject(NVRenderBackendTextureObject to,
+ NVRenderTextureTargetType::Enum target,
+ QT3DSI32 baseLevel, QT3DSI32 maxLevel)
+ {
+ NVRENDER_BACKEND_UNUSED(to);
+
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_BASE_LEVEL, baseLevel));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MAX_LEVEL, maxLevel));
+ }
+
+ void NVRenderBackendGL3Impl::UpdateTextureSwizzle(NVRenderBackendTextureObject to,
+ NVRenderTextureTargetType::Enum target,
+ NVRenderTextureSwizzleMode::Enum swizzleMode)
+ {
+ NVRENDER_BACKEND_UNUSED(to);
+ if (m_backendSupport.caps.bits.bTextureSwizzleSupported) {
+ GLint glSwizzle[4];
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+ m_Conversion.NVRenderConvertSwizzleModeToGL(swizzleMode, glSwizzle);
+#if defined(QT_OPENGL_ES)
+ // since ES3 spec has no GL_TEXTURE_SWIZZLE_RGBA set it separately
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_R, glSwizzle[0]));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_G, glSwizzle[1]));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_B, glSwizzle[2]));
+ GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_A, glSwizzle[3]));
+#else
+ GL_CALL_EXTRA_FUNCTION(glTexParameteriv(glTarget, GL_TEXTURE_SWIZZLE_RGBA, glSwizzle));
+#endif
+ }
+ }
+
+ QT3DSU32
+ NVRenderBackendGL3Impl::GetDepthBits() const
+ {
+ QT3DSI32 depthBits;
+ GL_CALL_EXTRA_FUNCTION(glGetFramebufferAttachmentParameteriv(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, &depthBits));
+
+ return depthBits;
+ }
+
+ QT3DSU32
+ NVRenderBackendGL3Impl::GetStencilBits() const
+ {
+ QT3DSI32 stencilBits;
+ GL_CALL_EXTRA_FUNCTION(glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+ &stencilBits));
+
+ return stencilBits;
+ }
+
+ void NVRenderBackendGL3Impl::GenerateMipMaps(NVRenderBackendTextureObject to,
+ NVRenderTextureTargetType::Enum target,
+ NVRenderHint::Enum /*genType*/)
+ {
+ GLuint texID = HandleToID_cast(GLuint, size_t, to);
+ GLenum glTarget = m_Conversion.fromTextureTargetToGL(target);
+ GL_CALL_EXTRA_FUNCTION(glActiveTexture(GL_TEXTURE0));
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
+ GL_CALL_EXTRA_FUNCTION(glGenerateMipmap(glTarget));
+ GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
+ }
+
+ bool NVRenderBackendGL3Impl::SetInputAssembler(NVRenderBackendInputAssemblerObject iao,
+ NVRenderBackendShaderProgramObject po)
+ {
+ if (iao == NULL) {
+ // unbind and return;
+ GL_CALL_EXTRA_FUNCTION(glBindVertexArray(0));
+ return true;
+ }
+
+ NVRenderBackendInputAssemblerGL *inputAssembler = (NVRenderBackendInputAssemblerGL *)iao;
+ NVRenderBackendAttributeLayoutGL *attribLayout = inputAssembler->m_attribLayout;
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+ NVDataRef<NVRenderBackendShaderInputEntryGL> shaderAttribBuffer;
+ if (pProgram->m_shaderInput)
+ shaderAttribBuffer = pProgram->m_shaderInput->m_ShaderInputEntries;
+
+ if (attribLayout->m_LayoutAttribEntries.size() < shaderAttribBuffer.size())
+ return false;
+
+ if (inputAssembler->m_VertexbufferHandles.size() <= attribLayout->m_MaxInputSlot) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ if (inputAssembler->m_VaoID == 0) {
+ // generate vao
+ GL_CALL_EXTRA_FUNCTION(glGenVertexArrays(1, &inputAssembler->m_VaoID));
+ QT3DS_ASSERT(inputAssembler->m_VaoID);
+ }
+
+ // set patch parameter count if changed
+ if (m_backendSupport.caps.bits.bTessellationSupported
+ && m_pCurrentMiscState->m_PatchVertexCount != inputAssembler->m_PatchVertexCount) {
+ m_pCurrentMiscState->m_PatchVertexCount = inputAssembler->m_PatchVertexCount;
+#if defined(QT_OPENGL_ES)
+ GL_CALL_TESSELATION_EXT(glPatchParameteriEXT(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount));
+#else
+ GL_CALL_TESSELATION_EXT(glPatchParameteri(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount));
+#endif
+ }
+
+ if (inputAssembler->m_cachedShaderHandle != programID) {
+ GL_CALL_EXTRA_FUNCTION(glBindVertexArray(inputAssembler->m_VaoID));
+ inputAssembler->m_cachedShaderHandle = programID;
+
+ QT3DS_FOREACH(idx, shaderAttribBuffer.size())
+ {
+ const NVRenderBackendShaderInputEntryGL &attrib(shaderAttribBuffer[idx]);
+ NVRenderBackendLayoutEntryGL *entry =
+ attribLayout->getEntryByName(attrib.m_AttribName);
+
+ if (entry) {
+ NVRenderBackendLayoutEntryGL &entryData(*entry);
+ if (entryData.m_Type != attrib.m_Type
+ || entryData.m_NumComponents != attrib.m_NumComponents) {
+ qCCritical(INVALID_OPERATION, "Attrib %s doesn't match vertex layout",
+ attrib.m_AttribName.c_str());
+ QT3DS_ASSERT(false);
+ return false;
+ } else {
+ entryData.m_AttribIndex = attrib.m_AttribLocation;
+ }
+ } else {
+ qCWarning(WARNING, "Failed to Bind attribute %s", attrib.m_AttribName.c_str());
+ }
+ }
+
+ // disable max possible used first
+ // this is currently sufficient since we always re-arrange input attributes from 0
+ for (QT3DSU32 i = 0; i < attribLayout->m_LayoutAttribEntries.size(); i++) {
+ GL_CALL_EXTRA_FUNCTION(glDisableVertexAttribArray(i));
+ }
+
+ // setup all attribs
+ QT3DS_FOREACH(idx, shaderAttribBuffer.size())
+ {
+ NVRenderBackendLayoutEntryGL *entry =
+ attribLayout->getEntryByName(shaderAttribBuffer[idx].m_AttribName);
+ if (entry) {
+ const NVRenderBackendLayoutEntryGL &entryData(*entry);
+ GLuint id = HandleToID_cast(
+ GLuint, size_t,
+ inputAssembler->m_VertexbufferHandles.mData[entryData.m_InputSlot]);
+ GL_CALL_EXTRA_FUNCTION(glBindBuffer(GL_ARRAY_BUFFER, id));
+ GL_CALL_EXTRA_FUNCTION(glEnableVertexAttribArray(entryData.m_AttribIndex));
+ GLuint offset = inputAssembler->m_offsets[entryData.m_InputSlot];
+ GLuint stride = inputAssembler->m_strides[entryData.m_InputSlot];
+ GL_CALL_EXTRA_FUNCTION(glVertexAttribPointer(
+ entryData.m_AttribIndex, entryData.m_NumComponents, GL_FLOAT, GL_FALSE,
+ stride, (const void *)(entryData.m_Offset + offset)));
+
+ } else {
+ GL_CALL_EXTRA_FUNCTION(glDisableVertexAttribArray(idx));
+ }
+ }
+
+ // setup index buffer.
+ if (inputAssembler->m_IndexbufferHandle) {
+ GL_CALL_EXTRA_FUNCTION(glBindBuffer(
+ GL_ELEMENT_ARRAY_BUFFER,
+ HandleToID_cast(GLuint, size_t, inputAssembler->m_IndexbufferHandle)));
+ } else {
+ GL_CALL_EXTRA_FUNCTION(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+ }
+ } else {
+ GL_CALL_EXTRA_FUNCTION(glBindVertexArray(inputAssembler->m_VaoID));
+ }
+#ifdef _DEBUG
+ if (inputAssembler->m_VaoID) {
+ QT3DS_FOREACH(idx, shaderAttribBuffer.size())
+ {
+ const NVRenderBackendShaderInputEntryGL &attrib(shaderAttribBuffer[idx]);
+ NVRenderBackendLayoutEntryGL *entry =
+ attribLayout->getEntryByName(attrib.m_AttribName);
+
+ if (entry) {
+ NVRenderBackendLayoutEntryGL &entryData(*entry);
+ if (entryData.m_Type != attrib.m_Type
+ || entryData.m_NumComponents != attrib.m_NumComponents
+ || entryData.m_AttribIndex != attrib.m_AttribLocation) {
+ qCCritical(INVALID_OPERATION, "Attrib %s doesn't match vertex layout",
+ attrib.m_AttribName.c_str());
+ QT3DS_ASSERT(false);
+ }
+ } else {
+ qCWarning(WARNING, "Failed to Bind attribute %s", attrib.m_AttribName.c_str());
+ }
+ }
+ }
+#endif // _DEBUG
+
+ return true;
+ }
+
+ void NVRenderBackendGL3Impl::SetDrawBuffers(NVRenderBackendRenderTargetObject rto,
+ NVConstDataRef<QT3DSI32> inDrawBufferSet)
+ {
+ NVRENDER_BACKEND_UNUSED(rto);
+
+ m_DrawBuffersArray.clear();
+
+ for (QT3DSU32 idx = 0, end = inDrawBufferSet.size(); idx < end; ++idx) {
+ if (inDrawBufferSet[idx] < 0)
+ m_DrawBuffersArray.push_back(GL_NONE);
+ else
+ m_DrawBuffersArray.push_back(GL_COLOR_ATTACHMENT0 + inDrawBufferSet[idx]);
+ }
+
+ GL_CALL_EXTRA_FUNCTION(glDrawBuffers((int)m_DrawBuffersArray.size(), m_DrawBuffersArray.data()));
+ }
+
+ void NVRenderBackendGL3Impl::SetReadBuffer(NVRenderBackendRenderTargetObject rto,
+ NVReadFaces::Enum inReadFace)
+ {
+ NVRENDER_BACKEND_UNUSED(rto);
+
+ GL_CALL_EXTRA_FUNCTION(glReadBuffer(m_Conversion.fromReadFacesToGL(inReadFace)));
+ }
+
+ void NVRenderBackendGL3Impl::RenderTargetAttach(NVRenderBackendRenderTargetObject,
+ NVRenderFrameBufferAttachments::Enum attachment,
+ NVRenderBackendTextureObject to, QT3DSI32 level,
+ QT3DSI32 layer)
+ {
+ // rto must be the current render target
+ GLuint texID = HandleToID_cast(GLuint, size_t, to);
+
+ GLenum glAttach = GLConversion::fromFramebufferAttachmentsToGL(attachment);
+
+ GL_CALL_EXTRA_FUNCTION(glFramebufferTextureLayer(GL_FRAMEBUFFER, glAttach, texID, level, layer))
+ }
+
+ void NVRenderBackendGL3Impl::SetReadTarget(NVRenderBackendRenderTargetObject rto)
+ {
+ GLuint fboID = HandleToID_cast(GLuint, size_t, rto);
+
+ GL_CALL_EXTRA_FUNCTION(glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID));
+ }
+
+ void NVRenderBackendGL3Impl::BlitFramebuffer(QT3DSI32 srcX0, QT3DSI32 srcY0, QT3DSI32 srcX1, QT3DSI32 srcY1,
+ QT3DSI32 dstX0, QT3DSI32 dstY0, QT3DSI32 dstX1, QT3DSI32 dstY1,
+ NVRenderClearFlags flags,
+ NVRenderTextureMagnifyingOp::Enum filter)
+ {
+ GL_CALL_EXTRA_FUNCTION(glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
+ m_Conversion.fromClearFlagsToGL(flags),
+ m_Conversion.fromTextureMagnifyingOpToGL(filter)));
+ }
+
+ void *NVRenderBackendGL3Impl::MapBuffer(NVRenderBackendBufferObject,
+ NVRenderBufferBindFlags bindFlags, size_t offset,
+ size_t length, NVRenderBufferAccessFlags accessFlags)
+ {
+ void *ret = NULL;
+ ret = GL_CALL_EXTRA_FUNCTION(glMapBufferRange(m_Conversion.fromBindBufferFlagsToGL(bindFlags), offset,
+ length, m_Conversion.fromBufferAccessBitToGL(accessFlags)));
+
+ return ret;
+ }
+
+ bool NVRenderBackendGL3Impl::UnmapBuffer(NVRenderBackendBufferObject,
+ NVRenderBufferBindFlags bindFlags)
+ {
+ GLboolean ret;
+
+ ret = GL_CALL_EXTRA_FUNCTION(glUnmapBuffer(m_Conversion.fromBindBufferFlagsToGL(bindFlags)));
+
+ return (ret) ? true : false;
+ }
+
+ QT3DSI32 NVRenderBackendGL3Impl::GetConstantBufferCount(NVRenderBackendShaderProgramObject po)
+ {
+ QT3DS_ASSERT(po);
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+
+ GLint numUniformBuffers;
+ GL_CALL_EXTRA_FUNCTION(glGetProgramiv(programID, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBuffers));
+
+ return numUniformBuffers;
+ }
+
+ QT3DSI32
+ NVRenderBackendGL3Impl::GetConstantBufferInfoByID(NVRenderBackendShaderProgramObject po,
+ QT3DSU32 id, QT3DSU32 nameBufSize,
+ QT3DSI32 *paramCount, QT3DSI32 *bufferSize,
+ QT3DSI32 *length, char *nameBuf)
+ {
+ QT3DS_ASSERT(po);
+ QT3DS_ASSERT(length);
+ QT3DS_ASSERT(nameBuf);
+
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+ GLuint blockIndex = GL_INVALID_INDEX;
+
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockName(programID, id, nameBufSize, length, nameBuf));
+
+ if (*length > 0) {
+ blockIndex = GL_CALL_EXTRA_FUNCTION(glGetUniformBlockIndex(programID, nameBuf));
+ if (blockIndex != GL_INVALID_INDEX) {
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, blockIndex,
+ GL_UNIFORM_BLOCK_DATA_SIZE, bufferSize));
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, blockIndex,
+ GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, paramCount));
+ }
+ }
+
+ return blockIndex;
+ }
+
+ void
+ NVRenderBackendGL3Impl::GetConstantBufferParamIndices(NVRenderBackendShaderProgramObject po,
+ QT3DSU32 id, QT3DSI32 *indices)
+ {
+ QT3DS_ASSERT(po);
+ QT3DS_ASSERT(indices);
+
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+
+ if (indices) {
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, id,
+ GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices));
+ }
+ }
+
+ void NVRenderBackendGL3Impl::GetConstantBufferParamInfoByIndices(
+ NVRenderBackendShaderProgramObject po, QT3DSU32 count, QT3DSU32 *indices, QT3DSI32 *type,
+ QT3DSI32 *size, QT3DSI32 *offset)
+ {
+ QT3DS_ASSERT(po);
+ QT3DS_ASSERT(count);
+ QT3DS_ASSERT(indices);
+
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+
+ if (count && indices) {
+ if (type) {
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformsiv(programID, count, indices, GL_UNIFORM_TYPE, type));
+ // convert to UIC types
+ QT3DS_FOREACH(idx, count)
+ {
+ type[idx] = m_Conversion.fromShaderGLToPropertyDataTypes(type[idx]);
+ }
+ }
+ if (size) {
+ GL_CALL_EXTRA_FUNCTION(glGetActiveUniformsiv(programID, count, indices, GL_UNIFORM_SIZE, size));
+ }
+ if (offset) {
+ GL_CALL_EXTRA_FUNCTION(
+ glGetActiveUniformsiv(programID, count, indices, GL_UNIFORM_OFFSET, offset));
+ }
+ }
+ }
+
+ void NVRenderBackendGL3Impl::ProgramSetConstantBlock(NVRenderBackendShaderProgramObject po,
+ QT3DSU32 blockIndex, QT3DSU32 binding)
+ {
+ NVRenderBackendShaderProgramGL *pProgram = (NVRenderBackendShaderProgramGL *)po;
+ GLuint programID = static_cast<GLuint>(pProgram->m_ProgramID);
+
+ GL_CALL_EXTRA_FUNCTION(glUniformBlockBinding(programID, blockIndex, binding));
+ }
+
+ void NVRenderBackendGL3Impl::ProgramSetConstantBuffer(QT3DSU32 index,
+ NVRenderBackendBufferObject bo)
+ {
+ QT3DS_ASSERT(bo);
+
+ GLuint bufID = HandleToID_cast(GLuint, size_t, bo);
+ GL_CALL_EXTRA_FUNCTION(glBindBufferBase(GL_UNIFORM_BUFFER, index, bufID));
+ }
+
+ NVRenderBackend::NVRenderBackendQueryObject NVRenderBackendGL3Impl::CreateQuery()
+ {
+ QT3DSU32 glQueryID = 0;
+
+ GL_CALL_EXTRA_FUNCTION(glGenQueries(1, &glQueryID));
+
+ return (NVRenderBackendQueryObject)glQueryID;
+ }
+
+ void NVRenderBackendGL3Impl::ReleaseQuery(NVRenderBackendQueryObject qo)
+ {
+ GLuint queryID = HandleToID_cast(GLuint, size_t, qo);
+
+ GL_CALL_EXTRA_FUNCTION(glDeleteQueries(1, &queryID));
+ }
+
+ void NVRenderBackendGL3Impl::BeginQuery(NVRenderBackendQueryObject qo,
+ NVRenderQueryType::Enum type)
+ {
+ GLuint queryID = HandleToID_cast(GLuint, size_t, qo);
+
+ GL_CALL_EXTRA_FUNCTION(glBeginQuery(m_Conversion.fromQueryTypeToGL(type), queryID));
+ }
+
+ void NVRenderBackendGL3Impl::EndQuery(NVRenderBackendQueryObject, NVRenderQueryType::Enum type)
+ {
+ GL_CALL_EXTRA_FUNCTION(glEndQuery(m_Conversion.fromQueryTypeToGL(type)));
+ }
+
+ void NVRenderBackendGL3Impl::GetQueryResult(NVRenderBackendQueryObject qo,
+ NVRenderQueryResultType::Enum resultType,
+ QT3DSU32 *params)
+ {
+ GLuint queryID = HandleToID_cast(GLuint, size_t, qo);
+
+ if (params)
+ GL_CALL_EXTRA_FUNCTION(glGetQueryObjectuiv(
+ queryID, m_Conversion.fromQueryResultTypeToGL(resultType), params));
+ }
+
+ void NVRenderBackendGL3Impl::GetQueryResult(NVRenderBackendQueryObject qo,
+ NVRenderQueryResultType::Enum resultType,
+ QT3DSU64 *params)
+ {
+ if (m_backendSupport.caps.bits.bTimerQuerySupported) {
+ GLuint queryID = HandleToID_cast(GLuint, size_t, qo);
+
+ if (params)
+#if defined(QT_OPENGL_ES)
+ GL_CALL_TIMER_EXT(glGetQueryObjectui64vEXT(
+ queryID, m_Conversion.fromQueryResultTypeToGL(resultType), params));
+#else
+ GL_CALL_TIMER_EXT(glGetQueryObjectui64v(
+ queryID, m_Conversion.fromQueryResultTypeToGL(resultType), params));
+#endif
+ }
+ }
+
+ void NVRenderBackendGL3Impl::SetQueryTimer(NVRenderBackendQueryObject qo)
+ {
+ if (m_backendSupport.caps.bits.bTimerQuerySupported) {
+ GLuint queryID = HandleToID_cast(GLuint, size_t, qo);
+#if defined(QT_OPENGL_ES)
+ GL_CALL_TIMER_EXT(glQueryCounterEXT(queryID, GL_TIMESTAMP_EXT));
+#else
+ GL_CALL_TIMER_EXT(glQueryCounter(queryID, GL_TIMESTAMP));
+#endif
+ }
+ }
+
+ NVRenderBackend::NVRenderBackendSyncObject
+ NVRenderBackendGL3Impl::CreateSync(NVRenderSyncType::Enum syncType, NVRenderSyncFlags)
+ {
+ GLsync syncID = 0;
+
+ syncID = GL_CALL_EXTRA_FUNCTION(glFenceSync(m_Conversion.fromSyncTypeToGL(syncType), 0));
+
+ return NVRenderBackendSyncObject(syncID);
+ }
+
+ void NVRenderBackendGL3Impl::ReleaseSync(NVRenderBackendSyncObject so)
+ {
+ GLsync syncID = (GLsync)so;
+
+ GL_CALL_EXTRA_FUNCTION(glDeleteSync(syncID));
+ }
+
+ void NVRenderBackendGL3Impl::WaitSync(NVRenderBackendSyncObject so, NVRenderCommandFlushFlags,
+ QT3DSU64)
+ {
+ GLsync syncID = (GLsync)so;
+
+ GL_CALL_EXTRA_FUNCTION(glWaitSync(syncID, 0, GL_TIMEOUT_IGNORED));
+ }
+}
+}