diff options
author | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-06 16:22:02 +0300 |
---|---|---|
committer | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-07 13:52:44 +0300 |
commit | b4954701093739e7a4e54a0669f306922d0d4605 (patch) | |
tree | 73d71319a921234f6b507c9098fdc842f7fe06dc /src/hdr | |
parent | 8548a5f5579e3eee7e5ae6b1f6901dcc8bfee19e (diff) |
Long live the slayer!
Initial commit of OpenGL Runtime to repository.
Based on SHA1 61823aaccc6510699a54b34a2fe3f7523dab3b4e
of qt3dstudio repository.
Task-number: QT3DS-3600
Change-Id: Iaeb80237399f0e5656a19ebec9d1ab3a681d8832
Reviewed-by: Pasi Keränen <pasi.keranen@qt.io>
Diffstat (limited to 'src/hdr')
-rw-r--r-- | src/hdr/CUDABSDFMipmap.cpp | 145 | ||||
-rw-r--r-- | src/hdr/CUDABSDFMipmap.h | 77 | ||||
-rw-r--r-- | src/hdr/GLComputeMipMap.h | 74 | ||||
-rw-r--r-- | src/hdr/GLComputeMipmap.cpp | 394 | ||||
-rw-r--r-- | src/hdr/HDR.cpp | 30 | ||||
-rw-r--r-- | src/hdr/HDR.h | 239 | ||||
-rw-r--r-- | src/hdr/MipmapBSDF.cpp | 265 | ||||
-rw-r--r-- | src/hdr/MipmapBSDF.cu | 404 | ||||
-rw-r--r-- | src/hdr/MipmapBSDF.h | 104 |
9 files changed, 1732 insertions, 0 deletions
diff --git a/src/hdr/CUDABSDFMipmap.cpp b/src/hdr/CUDABSDFMipmap.cpp new file mode 100644 index 0000000..94f6712 --- /dev/null +++ b/src/hdr/CUDABSDFMipmap.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifdef PLATFORM_HAS_CUDA + +#include "CUDABSDFMipmap.h" +#include "cuda.h" +#include "cuda_runtime.h" +#include "cuda_gl_interop.h" +#include "render/backends/Qt3DSRenderBackend.h" +#include "render/Qt3DSRenderTexture2D.h" +#include "foundation/Qt3DSRefCounted.h" +#include "nv_log.h" + +using namespace qt3ds; +using namespace qt3ds::render; +using namespace qt3ds::foundation; + +__host__ void jerror1(cudaError error); +#ifdef _DEBUG +#define CHECK_AND_HANDLE_CUDA_ERROR(func) \ + func; \ + { \ + cudaError error = cudaGetLastError(); \ + if (error != cudaSuccess) { \ + printf("%s\n", cudaGetErrorString(error)); \ + jerror1(error); \ + QT3DS_ASSERT(false); \ + } \ + } +#else +#define CHECK_AND_HANDLE_CUDA_ERROR(func) func; +#endif + +CUDABSDFMipMap::CUDABSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture2D, + NVRenderTextureFormats::Enum inDestFormat, NVFoundationBase &inFnd) + : BSDFMipMap(inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd) + , m_TextureBinded(false) +{ + + // CHECK_AND_HANDLE_CUDA_ERROR( cudaFree( 0 ); ) + m_Pitches = (size_t *)QT3DS_ALLOC(m_Foundation.getAllocator(), + sizeof(size_t) * m_MaxMipMapLevel + 1, "BSDF MipMap pitches"); + md_MipMapsData = (void **)QT3DS_ALLOC(m_Foundation.getAllocator(), + sizeof(void *) * m_MaxMipMapLevel + 1, "BSDF MipMap data"); + // CHECK_AND_HANDLE_CUDA_ERROR(); + size_t imagePitch; + int width = m_Width; + int height = m_Height; + + for (int i = 0; i <= m_MaxMipMapLevel; ++i) { + imagePitch = m_SizeOfFormat * width; + // checkCudaErrors(cudaMalloc((void **)&cuda_dest_resource[mip], size_tex_data)); + CHECK_AND_HANDLE_CUDA_ERROR( + cudaMallocPitch((void **)&md_MipMapsData[i], &m_Pitches[i], imagePitch, height);) + CHECK_AND_HANDLE_CUDA_ERROR(cudaMemset(md_MipMapsData[i], -1, m_Pitches[i] * height);) + + width = width > 2 ? width >> 1 : 1; + height = height > 2 ? height >> 1 : 1; + } +} + +CUDABSDFMipMap::~CUDABSDFMipMap() +{ + // CHECK_AND_HANDLE_CUDA_ERROR( cudaDeviceReset(); ) + CHECK_AND_HANDLE_CUDA_ERROR(cudaDeviceSynchronize();) + for (int i = 0; i <= m_MaxMipMapLevel; ++i) { + CHECK_AND_HANDLE_CUDA_ERROR(cudaFree(md_MipMapsData[i]);) + } + QT3DS_FREE(m_Foundation.getAllocator(), md_MipMapsData); + QT3DS_FREE(m_Foundation.getAllocator(), m_Pitches); +} + +void CUDABSDFMipMap::BindTexture() +{ + if (!m_TextureBinded) { + m_TextureBinded = true; + + int width = m_Width; + int height = m_Height; + for (int i = 0; i <= m_MaxMipMapLevel; ++i) { + // if you wwant to change some texture filter settings use m_Texture2D object + m_Texture2D.SetTextureData(NVDataRef<QT3DSU8>(), (QT3DSU8)i, width, height, + NVRenderTextureFormats::RGBA16F, + NVRenderTextureFormats::RGBA16F); + + width = width > 2 ? width >> 1 : 1; + height = height > 2 ? height >> 1 : 1; + } + // CHECK_AND_HANDLE_CUDA_ERROR( cudaGraphicsGLRegisterImage( &m_CudaMipMapResource, + // (GLuint)m_TextureHandle, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard | + // cudaGraphicsRegisterFlagsTextureGather) ) + CHECK_AND_HANDLE_CUDA_ERROR(cudaGraphicsGLRegisterImage( + &m_CudaMipMapResource, (GLuint)m_TextureHandle, GL_TEXTURE_2D, + cudaGraphicsRegisterFlagsWriteDiscard | cudaGraphicsRegisterFlagsTextureGather)) + } +} + +void CUDABSDFMipMap::TransferTexture() // after cuda generation +{ + cudaArray *texturePtr; + CHECK_AND_HANDLE_CUDA_ERROR(cudaGraphicsMapResources(1, &m_CudaMipMapResource, 0)) + int width = m_Width; + int height = m_Height; + for (int i = 0; i <= m_MaxMipMapLevel; ++i) { + CHECK_AND_HANDLE_CUDA_ERROR( + cudaGraphicsSubResourceGetMappedArray(&texturePtr, m_CudaMipMapResource, 0, i)) + CHECK_AND_HANDLE_CUDA_ERROR(cudaMemcpy2DToArray(texturePtr, 0, 0, md_MipMapsData[i], + m_Pitches[i], width * m_SizeOfFormat, + height, cudaMemcpyDeviceToDevice)); + + width = width > 2 ? width >> 1 : 1; + height = height > 2 ? height >> 1 : 1; + } + CHECK_AND_HANDLE_CUDA_ERROR(cudaGraphicsUnmapResources(1, &m_CudaMipMapResource, 0)) +} + +#endif diff --git a/src/hdr/CUDABSDFMipmap.h b/src/hdr/CUDABSDFMipmap.h new file mode 100644 index 0000000..33e0b91 --- /dev/null +++ b/src/hdr/CUDABSDFMipmap.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef CUDABSDfMIPMAP_H +#define CUDABSDFMIPMAP_H +#include "foundation/Qt3DSVec3.h" +#include "foundation/Qt3DSSimpleTypes.h" +#include "foundation/Qt3DSPerfTimer.h" +#include "foundation/Qt3DSAtomic.h" +#include "render/Qt3DSRenderBaseTypes.h" +#include "render/backends/Qt3DSRenderBackend.h" +#include "MipmapBSDF.h" + +#include "Qt3DSRenderLoadedTexture.h" + +#include "Qt3DSTypes.h" +struct cudaGraphicsResource; +#ifdef _LINUXPLATFORM +#define __declspec(dllexport) +#define __cdecl + +#endif +using namespace qt3ds::render; + +class CUDABSDFMipMap : public BSDFMipMap +{ +public: + CUDABSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture, NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd); + ~CUDABSDFMipMap(); + void Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject inTextureHandle, + NVRenderTextureFormats::Enum inFormat); + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation); + +private: + void CreateBsdfMipMaps(qt3ds::render::SLoadedTexture &inLoadedImage, void **result, int width, + int height); //, qt3ds::foundation::IPerfTimer& inPerfTimer); + + void BindTexture(); + void TransferTexture(); + + cudaGraphicsResource *m_CudaMipMapResource; + void **md_MipMapsData; + size_t *m_Pitches; + NVRenderBackend::NVRenderBackendTextureObject m_TextureHandle; + bool m_TextureBinded; +}; + +#endif diff --git a/src/hdr/GLComputeMipMap.h b/src/hdr/GLComputeMipMap.h new file mode 100644 index 0000000..a1a7ce5 --- /dev/null +++ b/src/hdr/GLComputeMipMap.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef GLCOMPUTE_BSDF_MIMAP_H +#define GLCOMPUTE_BSDF_MIMAP_H + +#include "render/Qt3DSRenderBaseTypes.h" +#include "render/backends/Qt3DSRenderBackend.h" +#include "MipmapBSDF.h" + +#include "Qt3DSRenderLoadedTexture.h" +#include "Qt3DSTypes.h" + +using namespace qt3ds::render; + +class qt3ds::render::NVRenderContext; +class qt3ds::render::NVRenderShaderProgram; +class qt3ds::render::NVRenderTexture2D; + +class GLComputeMipMap : public BSDFMipMap +{ +public: + GLComputeMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture, NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd); + ~GLComputeMipMap(); + void Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject inTextureHandle, + NVRenderTextureFormats::Enum inFormat); + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation); + +private: + void CreateLevel0Tex(void *inTextureData, int inTextureDataSize, + NVRenderTextureFormats::Enum inFormat); + + NVScopedRefCounted<NVRenderShaderProgram> m_BSDFProgram; + NVScopedRefCounted<NVRenderShaderProgram> m_UploadProgram_RGBA8; + NVScopedRefCounted<NVRenderShaderProgram> m_UploadProgram_RGB8; + NVScopedRefCounted<NVRenderTexture2D> m_Level0Tex; + bool m_TextureCreated; + + void createComputeProgram(NVRenderContext *context); + NVRenderShaderProgram *getOrCreateUploadComputeProgram(NVRenderContext *context, + NVRenderTextureFormats::Enum inFormat); +}; + +#endif diff --git a/src/hdr/GLComputeMipmap.cpp b/src/hdr/GLComputeMipmap.cpp new file mode 100644 index 0000000..36b550d --- /dev/null +++ b/src/hdr/GLComputeMipmap.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** 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 "GLComputeMipMap.h" +#include "render/Qt3DSRenderTexture2D.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "render/Qt3DSRenderContext.h" +#include "nv_log.h" +#include <string> + +using namespace qt3ds; +using namespace qt3ds::render; +using namespace qt3ds::foundation; + +static const char *computeUploadShader(std::string &prog, NVRenderTextureFormats::Enum inFormat, + bool binESContext) +{ + if (binESContext) { + prog += "#version 310 es\n" + "#extension GL_ARB_compute_shader : enable\n" + "precision highp float;\n" + "precision highp int;\n" + "precision mediump image2D;\n"; + } else { + prog += "#version 430\n" + "#extension GL_ARB_compute_shader : enable\n"; + } + + if (inFormat == NVRenderTextureFormats::RGBA8) { + prog += "// Set workgroup layout;\n" + "layout (local_size_x = 16, local_size_y = 16) in;\n\n" + "layout (rgba8, binding = 1) uniform image2D inputImage;\n\n" + "layout (rgba16f, binding = 2) uniform image2D outputImage;\n\n" + "void main()\n" + "{\n" + " if ( gl_GlobalInvocationID.x >= gl_NumWorkGroups.x || gl_GlobalInvocationID.y " + ">= gl_NumWorkGroups.y )\n" + " return;\n" + " vec4 value = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.xy));\n" + " imageStore( outputImage, ivec2(gl_GlobalInvocationID.xy), value );\n" + "}\n"; + } else { + prog += "float convertToFloat( in uint inValue )\n" + "{\n" + " uint v = inValue & uint(0xFF);\n" + " float f = float(v)/256.0;\n" + " return f;\n" + "}\n"; + + prog += "int getMod( in int inValue, in int mod )\n" + "{\n" + " int v = mod * (inValue/mod);\n" + " return inValue - v;\n" + "}\n"; + + prog += "vec4 getRGBValue( in int byteNo, vec4 inVal, vec4 inVal1 )\n" + "{\n" + " vec4 result= vec4(0.0);\n" + " if( byteNo == 0) {\n" + " result.r = inVal.r;\n" + " result.g = inVal.g;\n" + " result.b = inVal.b;\n" + " }\n" + " else if( byteNo == 1) {\n" + " result.r = inVal.g;\n" + " result.g = inVal.b;\n" + " result.b = inVal.a;\n" + " }\n" + " else if( byteNo == 2) {\n" + " result.r = inVal.b;\n" + " result.g = inVal.a;\n" + " result.b = inVal1.r;\n" + " }\n" + " else if( byteNo == 3) {\n" + " result.r = inVal.a;\n" + " result.g = inVal1.r;\n" + " result.b = inVal1.g;\n" + " }\n" + " return result;\n" + "}\n"; + + prog += "// Set workgroup layout;\n" + "layout (local_size_x = 16, local_size_y = 16) in;\n\n" + "layout (rgba8, binding = 1) uniform image2D inputImage;\n\n" + "layout (rgba16f, binding = 2) uniform image2D outputImage;\n\n" + "void main()\n" + "{\n" + " vec4 result = vec4(0.0);\n" + " if ( gl_GlobalInvocationID.x >= gl_NumWorkGroups.x || gl_GlobalInvocationID.y " + ">= gl_NumWorkGroups.y )\n" + " return;\n" + " int xpos = (int(gl_GlobalInvocationID.x)*3)/4;\n" + " int xmod = getMod(int(gl_GlobalInvocationID.x)*3, 4);\n" + " ivec2 readPos = ivec2(xpos, gl_GlobalInvocationID.y);\n" + " vec4 value = imageLoad(inputImage, readPos);\n" + " vec4 value1 = imageLoad(inputImage, ivec2(readPos.x + 1, readPos.y));\n" + " result = getRGBValue( xmod, value, value1);\n" + " imageStore( outputImage, ivec2(gl_GlobalInvocationID.xy), result );\n" + "}\n"; + } + return prog.c_str(); +} + +static const char *computeWorkShader(std::string &prog, bool binESContext) +{ + if (binESContext) { + prog += "#version 310 es\n" + "#extension GL_ARB_compute_shader : enable\n" + "precision highp float;\n" + "precision highp int;\n" + "precision mediump image2D;\n"; + } else { + prog += "#version 430\n" + "#extension GL_ARB_compute_shader : enable\n"; + } + + prog += "int wrapMod( in int a, in int base )\n" + "{\n" + " return ( a >= 0 ) ? a % base : -(a % base) + base;\n" + "}\n"; + + prog += "void getWrappedCoords( inout int sX, inout int sY, in int width, in int height )\n" + "{\n" + " if (sY < 0) { sX -= width >> 1; sY = -sY; }\n" + " if (sY >= height) { sX += width >> 1; sY = height - sY; }\n" + " sX = wrapMod( sX, width );\n" + "}\n"; + + prog += "// Set workgroup layout;\n" + "layout (local_size_x = 16, local_size_y = 16) in;\n\n" + "layout (rgba16f, binding = 1) uniform image2D inputImage;\n\n" + "layout (rgba16f, binding = 2) uniform image2D outputImage;\n\n" + "void main()\n" + "{\n" + " int prevWidth = int(gl_NumWorkGroups.x) << 1;\n" + " int prevHeight = int(gl_NumWorkGroups.y) << 1;\n" + " if ( gl_GlobalInvocationID.x >= gl_NumWorkGroups.x || gl_GlobalInvocationID.y >= " + "gl_NumWorkGroups.y )\n" + " return;\n" + " vec4 accumVal = vec4(0.0);\n" + " for ( int sy = -2; sy <= 2; ++sy )\n" + " {\n" + " for ( int sx = -2; sx <= 2; ++sx )\n" + " {\n" + " int sampleX = sx + (int(gl_GlobalInvocationID.x) << 1);\n" + " int sampleY = sy + (int(gl_GlobalInvocationID.y) << 1);\n" + " getWrappedCoords(sampleX, sampleY, prevWidth, prevHeight);\n" + " if ((sampleY * prevWidth + sampleX) < 0 )\n" + " sampleY = prevHeight + sampleY;\n" + " ivec2 pos = ivec2(sampleX, sampleY);\n" + " vec4 value = imageLoad(inputImage, pos);\n" + " float filterPdf = 1.0 / ( 1.0 + float(sx*sx + sy*sy)*2.0 );\n" + " filterPdf /= 4.71238898;\n" + " accumVal[0] += filterPdf * value.r;\n" + " accumVal[1] += filterPdf * value.g;\n" + " accumVal[2] += filterPdf * value.b;\n" + " accumVal[3] += filterPdf * value.a;\n" + " }\n" + " }\n" + " imageStore( outputImage, ivec2(gl_GlobalInvocationID.xy), accumVal );\n" + "}\n"; + + return prog.c_str(); +} + +GLComputeMipMap::GLComputeMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture2D, + NVRenderTextureFormats::Enum inDestFormat, NVFoundationBase &inFnd) + : BSDFMipMap(inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd) + , m_BSDFProgram(NULL) + , m_UploadProgram_RGBA8(NULL) + , m_UploadProgram_RGB8(NULL) + , m_Level0Tex(NULL) + , m_TextureCreated(false) +{ +} + +GLComputeMipMap::~GLComputeMipMap() +{ + m_UploadProgram_RGB8 = NULL; + m_UploadProgram_RGBA8 = NULL; + m_BSDFProgram = NULL; + m_Level0Tex = NULL; +} + +inline NVConstDataRef<QT3DSI8> toRef(const char *data) +{ + size_t len = strlen(data) + 1; + return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len); +} + +static bool isGLESContext(NVRenderContext *context) +{ + NVRenderContextType ctxType = context->GetRenderContextType(); + + // Need minimum of GL3 or GLES3 + if (ctxType == NVRenderContextValues::GLES2 || ctxType == NVRenderContextValues::GLES3 + || ctxType == NVRenderContextValues::GLES31) { + return true; + } + + return false; +} + +#define WORKGROUP_SIZE 16 + +void GLComputeMipMap::createComputeProgram(NVRenderContext *context) +{ + std::string computeProg; + + if (!m_BSDFProgram) { + m_BSDFProgram = context + ->CompileComputeSource( + "Compute BSDF mipmap shader", + toRef(computeWorkShader(computeProg, isGLESContext(context)))) + .mShader; + } +} + +NVRenderShaderProgram * +GLComputeMipMap::getOrCreateUploadComputeProgram(NVRenderContext *context, + NVRenderTextureFormats::Enum inFormat) +{ + std::string computeProg; + + if (inFormat == NVRenderTextureFormats::RGB8) { + if (!m_UploadProgram_RGB8) { + m_UploadProgram_RGB8 = + context + ->CompileComputeSource( + "Compute BSDF mipmap level 0 RGB8 shader", + toRef(computeUploadShader(computeProg, inFormat, isGLESContext(context)))) + .mShader; + } + + return m_UploadProgram_RGB8; + } else { + if (!m_UploadProgram_RGBA8) { + m_UploadProgram_RGBA8 = + context + ->CompileComputeSource( + "Compute BSDF mipmap level 0 RGBA8 shader", + toRef(computeUploadShader(computeProg, inFormat, isGLESContext(context)))) + .mShader; + } + + return m_UploadProgram_RGBA8; + } +} + +void GLComputeMipMap::CreateLevel0Tex(void *inTextureData, int inTextureDataSize, + NVRenderTextureFormats::Enum inFormat) +{ + NVRenderTextureFormats::Enum theFormat = inFormat; + int theWidth = m_Width; + + // Since we cannot use RGB format in GL compute + // we treat it as a RGBA component format + if (inFormat == NVRenderTextureFormats::RGB8) { + // This works only with 4 byte aligned data + QT3DS_ASSERT(m_Width % 4 == 0); + theFormat = NVRenderTextureFormats::RGBA8; + theWidth = (m_Width * 3) / 4; + } + + if (m_Level0Tex == NULL) { + m_Level0Tex = m_NVRenderContext->CreateTexture2D(); + m_Level0Tex->SetTextureStorage(1, theWidth, m_Height, theFormat, theFormat, + NVDataRef<QT3DSU8>((QT3DSU8 *)inTextureData, inTextureDataSize)); + } else { + m_Level0Tex->SetTextureSubData(NVDataRef<QT3DSU8>((QT3DSU8 *)inTextureData, inTextureDataSize), 0, + 0, 0, theWidth, m_Height, theFormat); + } +} + +void GLComputeMipMap::Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject, + NVRenderTextureFormats::Enum inFormat) +{ + bool needMipUpload = (inFormat != m_DestinationFormat); + // re-upload data + if (!m_TextureCreated) { + m_Texture2D.SetTextureStorage( + m_MaxMipMapLevel + 1, m_Width, m_Height, m_DestinationFormat, inFormat, (needMipUpload) + ? NVDataRef<QT3DSU8>() + : NVDataRef<QT3DSU8>((QT3DSU8 *)inTextureData, inTextureDataSize)); + m_Texture2D.addRef(); + // create a compute shader (if not aloread done) which computes the BSDF mipmaps for this + // texture + createComputeProgram(m_NVRenderContext); + + if (!m_BSDFProgram) { + QT3DS_ASSERT(false); + return; + } + + m_TextureCreated = true; + } else if (!needMipUpload) { + m_Texture2D.SetTextureSubData(NVDataRef<QT3DSU8>((QT3DSU8 *)inTextureData, inTextureDataSize), 0, + 0, 0, m_Width, m_Height, inFormat); + } + + if (needMipUpload) { + CreateLevel0Tex(inTextureData, inTextureDataSize, inFormat); + } + + NVScopedRefCounted<NVRenderImage2D> theInputImage; + NVScopedRefCounted<NVRenderImage2D> theOutputImage; + theInputImage = + m_NVRenderContext->CreateImage2D(&m_Texture2D, NVRenderImageAccessType::ReadWrite); + theOutputImage = + m_NVRenderContext->CreateImage2D(&m_Texture2D, NVRenderImageAccessType::ReadWrite); + + if (needMipUpload && m_Level0Tex) { + NVRenderShaderProgram *uploadProg = + getOrCreateUploadComputeProgram(m_NVRenderContext, inFormat); + if (!uploadProg) + return; + + m_NVRenderContext->SetActiveShader(uploadProg); + + NVScopedRefCounted<NVRenderImage2D> theInputImage0; + theInputImage0 = + m_NVRenderContext->CreateImage2D(m_Level0Tex, NVRenderImageAccessType::ReadWrite); + + theInputImage0->SetTextureLevel(0); + NVRenderCachedShaderProperty<NVRenderImage2D *> theCachedinputImage0("inputImage", + *uploadProg); + theCachedinputImage0.Set(theInputImage0); + + theOutputImage->SetTextureLevel(0); + NVRenderCachedShaderProperty<NVRenderImage2D *> theCachedOutputImage("outputImage", + *uploadProg); + theCachedOutputImage.Set(theOutputImage); + + m_NVRenderContext->DispatchCompute(uploadProg, m_Width, m_Height, 1); + + // sync + NVRenderBufferBarrierFlags flags(NVRenderBufferBarrierValues::ShaderImageAccess); + m_NVRenderContext->SetMemoryBarrier(flags); + } + + int width = m_Width >> 1; + int height = m_Height >> 1; + + m_NVRenderContext->SetActiveShader(m_BSDFProgram); + + for (int i = 1; i <= m_MaxMipMapLevel; ++i) { + theOutputImage->SetTextureLevel(i); + NVRenderCachedShaderProperty<NVRenderImage2D *> theCachedOutputImage("outputImage", + *m_BSDFProgram); + theCachedOutputImage.Set(theOutputImage); + theInputImage->SetTextureLevel(i - 1); + NVRenderCachedShaderProperty<NVRenderImage2D *> theCachedinputImage("inputImage", + *m_BSDFProgram); + theCachedinputImage.Set(theInputImage); + + m_NVRenderContext->DispatchCompute(m_BSDFProgram, width, height, 1); + + width = width > 2 ? width >> 1 : 1; + height = height > 2 ? height >> 1 : 1; + + // sync + NVRenderBufferBarrierFlags flags(NVRenderBufferBarrierValues::ShaderImageAccess); + m_NVRenderContext->SetMemoryBarrier(flags); + } +} diff --git a/src/hdr/HDR.cpp b/src/hdr/HDR.cpp new file mode 100644 index 0000000..9abe2b3 --- /dev/null +++ b/src/hdr/HDR.cpp @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** 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 "HDR.h" diff --git a/src/hdr/HDR.h b/src/hdr/HDR.h new file mode 100644 index 0000000..fbc4ea4 --- /dev/null +++ b/src/hdr/HDR.h @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#pragma once +#ifndef HDR_H +#define HDR_H + +#include "foundation/Qt3DSVec3.h" +//#include "HDR.h" + +namespace qt3ds { +class QT3DSVec3; + +namespace HDR { + + template <int N> + class HDRConfiguration; + + template <int N> + class Histogram + { + public: + /** + * @brief build the histogram based on 2^10 binning. + * + * @param[in] inImage Pointer to image + * @param[in] inWidth Width of image + * @param[in] inHeight Height of image + * @param[out] outHistogram + * + * @return No return + */ + static void Build(QT3DSVec3 *inImage, int inWidth, int inHeight, QT3DSVec3 *outHistogram) + { + long noPixels = inWidth * inHeight; + + for (int i = 0; i < noPixels; ++i) { + outHistogram[(int)inImage[i].x].x++; + outHistogram[(int)inImage[i].y].y++; + outHistogram[(int)inImage[i].z].z++; + } + } + }; + + template <int N> + class HDR + { + + public: + HDR(HDRConfiguration<N> *inConfiguration) { mHDRConfiguration = inConfiguration; } + + void Build(QT3DSVec3 **inImages, int inNoImages, int inWidth, int inHeight, float *inExposures, + QT3DSVec3 *outRadiance) + { + for (int x = 0; x < inWidth; ++x) { + for (int y = 0; y < inHeight; ++y) { + QT3DSVec3 divisor(0.0f); + QT3DSVec3 dividend(0.0f); + for (int i = 0; i < inNoImages; ++i) { + QT3DSVec3 pixel = inImages[i][x + y * inWidth]; + + dividend += (LUT(mHDRConfiguration->weights, pixel) * inExposures[i]) + .multiply(LUT(mHDRConfiguration->CRF, pixel)); + divisor += LUT(mHDRConfiguration->weights, pixel) * inExposures[i] + * inExposures[i]; + } + divisor.x = 1.0f / divisor.x; + divisor.y = 1.0f / divisor.y; + divisor.z = 1.0f / divisor.z; + + outRadiance[x + y * inWidth] = dividend.multiply(divisor); + } + } + } + + private: + /** + * @brief Return the value based off from array as a LUT + * + * @param[in] inLUT The LUT table of interest + * @param[in] inValue The value that you have + * @param[out] QT3DSVec3 The corresponding value of array based on input + * tuple + * + * @return No return + */ + QT3DSVec3 LUT(float *inLUT, QT3DSVec3 inValue) + { + return QT3DSVec3(inLUT[(int)inValue.x], inLUT[(int)inValue.y], inLUT[(int)inValue.z]); + } + + QT3DSVec3 LUT(QT3DSVec3 *inLUT, QT3DSVec3 inValue) + { + return QT3DSVec3(inLUT[(int)inValue.x].x, inLUT[(int)inValue.y].y, + inLUT[(int)inValue.z].z); + } + + HDRConfiguration<N> *mHDRConfiguration; + }; + + template <int N> + class HDRConfiguration + { + public: + HDRConfiguration() + { + threshold = 0.1f; + maxIterations = 30; + GenerateRobertsonWeighting(); + } + + void SetCRF(QT3DSVec3 *inCRF) { memcpy(CRF, inCRF, sizeof(QT3DSVec3) * N); } + + /** + * @brief build the camera response function + * + * @param[in] inImages Pointer to images + * @param[in] inNoImages Number of images + * @param[in] inWidth Width of image + * @param[in] inHeight Height of image + * @param[out] outHistogram + * + * @return No return + */ + void BuildCRF(QT3DSVec3 **inImages, int inNoImages, int inWidth, int inHeight, + float *inExposures) + { + QT3DSVec3 histogram[N]; + QT3DSVec3 newCRF[N]; + + HDR<N> hdr(this); + + memset(histogram, 0, sizeof(QT3DSVec3) * N); + + for (int i = 0; i < inNoImages; ++i) { + Histogram<N>::Build(inImages[i], inWidth, inHeight, histogram); + } + + for (int i = 0; i < N; ++i) { + histogram[i].x = histogram[i].x > 0 ? 1 / histogram[i].x : 0; + histogram[i].y = histogram[i].y > 0 ? 1 / histogram[i].y : 0; + histogram[i].z = histogram[i].z > 0 ? 1 / histogram[i].z : 0; + } + + QT3DSVec3 *radiance = new QT3DSVec3[inWidth * inHeight * sizeof(QT3DSVec3)]; + + // iteration 0, linearize CRF + for (int i = 0; i < N; ++i) { + CRF[i] = QT3DSVec3((float)i) * 2.0f / N; + } + + for (int iteration = 0; iteration < maxIterations; ++iteration) { + hdr.Build(inImages, inNoImages, inWidth, inHeight, inExposures, radiance); + + memset(newCRF, 0, sizeof(QT3DSVec3) * N); + + for (int i = 0; i < inNoImages; ++i) { + for (int x = 0; x < inWidth; ++x) { + for (int y = 0; y < inHeight; ++y) { + long offset = x + y * inWidth; + QT3DSVec3 pixel = inImages[i][offset]; + newCRF[(int)pixel.x].x += (inExposures[i] * radiance[offset].x); + newCRF[(int)pixel.y].y += (inExposures[i] * radiance[offset].y); + newCRF[(int)pixel.z].z += (inExposures[i] * radiance[offset].z); + } + } + } + + float difference = 0; + for (int i = 0; i < N; ++i) { + newCRF[i] = newCRF[i].multiply(histogram[i]); + } + + QT3DSVec3 middle = newCRF[N / 2]; + for (int i = 0; i < N; ++i) { + newCRF[i].x = newCRF[i].x / middle.x; + newCRF[i].y = newCRF[i].y / middle.y; + newCRF[i].z = newCRF[i].z / middle.z; + difference += (CRF[i] - newCRF[i]).magnitude(); + } + for (int i = 0; i < N; ++i) { + CRF[i] = newCRF[i]; + } + if (difference < threshold) { + break; + } + } + delete[] radiance; + } + + float weights[N]; + QT3DSVec3 CRF[N]; + + private: + void GenerateRobertsonWeighting() + { + // Dynamic Range Improvement Through Multiple Exposures (5) + // gaussian random weighting + float divisor = (N - 1) * (N - 1) / 4.0; + for (int i = 0; i < N; ++i) { + float dividend = (i - (N - 1) / 2.0f); + dividend *= dividend; + weights[i] = exp(-4.0f * dividend / divisor); + } + } + + int maxIterations; + float threshold; + }; +} +} +#endif diff --git a/src/hdr/MipmapBSDF.cpp b/src/hdr/MipmapBSDF.cpp new file mode 100644 index 0000000..fd57015 --- /dev/null +++ b/src/hdr/MipmapBSDF.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** 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 "MipmapBSDF.h" +#include "GLComputeMipMap.h" + +#ifdef PLATFORM_HAS_CUDA +#include "cuda.h" +#include "cuda_runtime.h" +#include "CUDABSDFMipmap.h" +#endif + +#include "render/Qt3DSRenderContext.h" +#include "render/Qt3DSRenderTexture2D.h" +#include "foundation/Qt3DSRefCounted.h" +#include "nv_log.h" + +using namespace qt3ds; +using namespace qt3ds::render; +using namespace qt3ds::foundation; + +BSDFMipMap::BSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture2D, NVRenderTextureFormats::Enum inDestFormat, + NVFoundationBase &inFnd) + : m_Foundation(inFnd) + , m_Texture2D(inTexture2D) + , m_Width(inWidth) + , m_Height(inHeight) + , m_DestinationFormat(inDestFormat) + , m_NVRenderContext(inNVRenderContext) +{ + // Calculate mip level + int maxDim = inWidth >= inHeight ? inWidth : inHeight; + + m_MaxMipMapLevel = static_cast<int>(logf((float)maxDim) / logf(2.0f)); + // no concept of sizeOfFormat just does'nt make sense + m_SizeOfFormat = NVRenderTextureFormats::getSizeofFormat(m_DestinationFormat); + m_NoOfComponent = NVRenderTextureFormats::getNumberOfComponent(m_DestinationFormat); +} + +BSDFMipMap *BSDFMipMap::Create(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture2D, + NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd) +{ + BSDFMipMap *theBSDFMipMap = NULL; +#ifdef PLATFORM_HAS_CUDA + int deviceCount; + cudaError_t e = cudaGetDeviceCount(&deviceCount); +#endif + + if (inNVRenderContext->IsComputeSupported()) { + theBSDFMipMap = QT3DS_NEW(inFnd.getAllocator(), GLComputeMipMap)( + inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd); + } else +#ifdef PLATFORM_HAS_CUDA + if (e == cudaSuccess && deviceCount > 0) { + theBSDFMipMap = QT3DS_NEW(inFnd.getAllocator(), CUDABSDFMipMap)( + inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd); + } else +#endif + if (!theBSDFMipMap) { + theBSDFMipMap = QT3DS_NEW(inFnd.getAllocator(), BasicBSDFMipMap)( + inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd); + } + + return theBSDFMipMap; +} + +BasicBSDFMipMap::BasicBSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture2D, + NVRenderTextureFormats::Enum inDestFormat, NVFoundationBase &inFnd) + : BSDFMipMap(inNVRenderContext, inWidth, inHeight, inTexture2D, inDestFormat, inFnd) +{ +} + +BSDFMipMap::~BSDFMipMap() +{ +} + +void BasicBSDFMipMap::Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject, + NVRenderTextureFormats::Enum inFormat) +{ + + m_InternalFormat = inFormat; + m_SizeOfInternalFormat = NVRenderTextureFormats::getSizeofFormat(m_InternalFormat); + m_InternalNoOfComponent = NVRenderTextureFormats::getNumberOfComponent(m_InternalFormat); + + m_Texture2D.SetTextureData(NVDataRef<QT3DSU8>((QT3DSU8 *)inTextureData, inTextureDataSize), 0, + m_Width, m_Height, inFormat, m_DestinationFormat); + + STextureData theMipImage; + STextureData prevImage; + prevImage.data = inTextureData; + prevImage.dataSizeInBytes = inTextureDataSize; + prevImage.format = inFormat; + int curWidth = m_Width; + int curHeight = m_Height; + int size = NVRenderTextureFormats::getSizeofFormat(m_InternalFormat); + for (int idx = 1; idx <= m_MaxMipMapLevel; ++idx) { + theMipImage = + CreateBsdfMipLevel(theMipImage, prevImage, curWidth, curHeight); //, m_PerfTimer ); + curWidth = curWidth >> 1; + curHeight = curHeight >> 1; + curWidth = curWidth >= 1 ? curWidth : 1; + curHeight = curHeight >= 1 ? curHeight : 1; + inTextureDataSize = curWidth * curHeight * size; + + m_Texture2D.SetTextureData(toU8DataRef((char *)theMipImage.data, (QT3DSU32)inTextureDataSize), + (QT3DSU8)idx, (QT3DSU32)curWidth, (QT3DSU32)curHeight, theMipImage.format, + m_DestinationFormat); + + if (prevImage.data == inTextureData) + prevImage = STextureData(); + + STextureData temp = prevImage; + prevImage = theMipImage; + theMipImage = temp; + } + QT3DS_FREE(m_Foundation.getAllocator(), theMipImage.data); + QT3DS_FREE(m_Foundation.getAllocator(), prevImage.data); +} + +inline int BasicBSDFMipMap::wrapMod(int a, int base) +{ + return (a >= 0) ? a % base : (a % base) + base; +} + +inline void BasicBSDFMipMap::getWrappedCoords(int &sX, int &sY, int width, int height) +{ + if (sY < 0) { + sX -= width >> 1; + sY = -sY; + } + if (sY >= height) { + sX += width >> 1; + sY = height - sY; + } + sX = wrapMod(sX, width); +} + +STextureData BasicBSDFMipMap::CreateBsdfMipLevel(STextureData &inCurMipLevel, + STextureData &inPrevMipLevel, int width, + int height) //, IPerfTimer& inPerfTimer ) +{ + // SStackPerfTimer __timer( inPerfTimer, "Image BSDF Mip Level" ); + STextureData retval; + int newWidth = width >> 1; + int newHeight = height >> 1; + newWidth = newWidth >= 1 ? newWidth : 1; + newHeight = newHeight >= 1 ? newHeight : 1; + + if (inCurMipLevel.data) { + retval = inCurMipLevel; + retval.dataSizeInBytes = + newWidth * newHeight * NVRenderTextureFormats::getSizeofFormat(inPrevMipLevel.format); + } else { + retval.dataSizeInBytes = + newWidth * newHeight * NVRenderTextureFormats::getSizeofFormat(inPrevMipLevel.format); + retval.format = inPrevMipLevel.format; // inLoadedImage.format; + retval.data = m_Foundation.getAllocator().allocate( + retval.dataSizeInBytes, "Bsdf Scaled Image Data", __FILE__, __LINE__); + } + + for (int y = 0; y < newHeight; ++y) { + for (int x = 0; x < newWidth; ++x) { + float accumVal[4]; + accumVal[0] = 0; + accumVal[1] = 0; + accumVal[2] = 0; + accumVal[3] = 0; + for (int sy = -2; sy <= 2; ++sy) { + for (int sx = -2; sx <= 2; ++sx) { + int sampleX = sx + (x << 1); + int sampleY = sy + (y << 1); + getWrappedCoords(sampleX, sampleY, width, height); + + // Cauchy filter (this is simply because it's the easiest to evaluate, and + // requires no complex + // functions). + float filterPdf = 1.f / (1.f + float(sx * sx + sy * sy) * 2.f); + // With FP HDR formats, we're not worried about intensity loss so much as + // unnecessary energy gain, + // whereas with LDR formats, the fear with a continuous normalization factor is + // that we'd lose + // intensity and saturation as well. + filterPdf /= (NVRenderTextureFormats::getSizeofFormat(retval.format) >= 8) + ? 4.71238898f + : 4.5403446f; + // filterPdf /= 4.5403446f; // Discrete normalization factor + // filterPdf /= 4.71238898f; // Continuous normalization factor + float curPix[4]; + QT3DSI32 byteOffset = (sampleY * width + sampleX) + * NVRenderTextureFormats::getSizeofFormat(retval.format); + if (byteOffset < 0) { + sampleY = height + sampleY; + byteOffset = (sampleY * width + sampleX) + * NVRenderTextureFormats::getSizeofFormat(retval.format); + } + + NVRenderTextureFormats::decodeToFloat(inPrevMipLevel.data, byteOffset, curPix, + retval.format); + + accumVal[0] += filterPdf * curPix[0]; + accumVal[1] += filterPdf * curPix[1]; + accumVal[2] += filterPdf * curPix[2]; + accumVal[3] += filterPdf * curPix[3]; + } + } + + /* + // Re-adjustment after the fact for the RGBD hack. + if (retval.format == NVRenderTextureFormats::RGBA8 || retval.format == + NVRenderTextureFormats::SRGB8A8) + { + float divVal = (accumVal[0] > accumVal[1]) ? accumVal[0] : accumVal[1]; + divVal = (divVal > accumVal[2]) ? divVal : accumVal[2]; + if (divVal > 1.0) + { + divVal = 1.0f / divVal; + accumVal[0] *= divVal; + accumVal[1] *= divVal; + accumVal[2] *= divVal; + accumVal[3] = divVal; + } + else + accumVal[3] = 1.0f; + } + */ + QT3DSU32 newIdx = + (y * newWidth + x) * NVRenderTextureFormats::getSizeofFormat(retval.format); + + NVRenderTextureFormats::encodeToPixel(accumVal, retval.data, newIdx, retval.format); + } + } + + return retval; +} diff --git a/src/hdr/MipmapBSDF.cu b/src/hdr/MipmapBSDF.cu new file mode 100644 index 0000000..6ddac4b --- /dev/null +++ b/src/hdr/MipmapBSDF.cu @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if defined (_PLATFORM_USE_EGL) +#include <GLES31/gl31.h> +#include <GLES31/gl2ext.h> +#endif + +#include "CUDABSDFMipmap.h" +#include "cuda.h" +#include "cuda_runtime.h" +#include "cuda_gl_interop.h" +#include <iostream> + +using namespace nv; +using namespace nv::render; +__host__ void jerror1(cudaError error) +{ + static int i = 0; + ++i; +} +#ifdef _DEBUG +#define CHECK_AND_HANDLE_CUDA_ERROR(func) \ + func; \ + { \ + cudaError error = cudaGetLastError(); \ + if ( error != cudaSuccess ) \ + { \ + printf("%s\n", cudaGetErrorString(error)); \ + jerror1(error);\ + NV_ASSERT( false ); \ + } \ + } +#else +#define CHECK_AND_HANDLE_CUDA_ERROR(func) \ +func; +#endif + +__device__ inline int wrapMod( int a, int base ) +{ + int ret = a % base; + if (ret < 0 ) ret += base; + return ret; +} + +__device__ inline void getWrappedCoords( int &sX, int &sY, int width, int height ) +{ + if (sY < 0) { sX -= width >> 1; sY = -sY; } + if (sY >= height) { sX += width >> 1; sY = height - sY; } + sX = wrapMod( sX, width ); + sY = wrapMod( sY, height ); +} + +__device__ void decodeToFloat( void *inPtr, NVU32 byteOfs, float *outPtr, NVRenderTextureFormats::Enum inFmt, unsigned int numberOfComponent ) +{ + outPtr[0] = 0.0f; outPtr[1] = 0.0f; outPtr[2] = 0.0f; outPtr[3] = 0.0f; + NVU8 *src = reinterpret_cast<NVU8 *>(inPtr); + //float divisor; // If we want to support RGBD? + switch(inFmt) + { + case NVRenderTextureFormats::Alpha8: + outPtr[0] = ((float)src[byteOfs]) / 255.0f; + break; + + case NVRenderTextureFormats::Luminance8: + case NVRenderTextureFormats::LuminanceAlpha8: + case NVRenderTextureFormats::R8: + case NVRenderTextureFormats::RG8: + case NVRenderTextureFormats::RGB8: + case NVRenderTextureFormats::RGBA8: + case NVRenderTextureFormats::SRGB8: + case NVRenderTextureFormats::SRGB8A8: + // NOTE : RGBD Hack here for reference. Not meant for installation. + //divisor = (NVRenderTextureFormats::getSizeofFormat(inFmt) == 4) ? ((float)src[byteOfs+3]) / 255.0f : 1.0f; + for ( NVU32 i = 0; i < numberOfComponent; ++i ) + { + float val = ((float)src[byteOfs + i]) / 255.0f; + outPtr[i] = (i < 3) ? powf(val, 0.4545454545f) : val; + // Assuming RGBA8 actually means RGBD (which is stupid, I know) + //if ( NVRenderTextureFormats::getSizeofFormat(inFmt) == 4 ) { outPtr[i] /= divisor; } + } + //outPtr[3] = divisor; + break; + + case NVRenderTextureFormats::RGBA32F: + outPtr[0] = reinterpret_cast<float *>(src+byteOfs)[0]; + outPtr[1] = reinterpret_cast<float *>(src+byteOfs)[1]; + outPtr[2] = reinterpret_cast<float *>(src+byteOfs)[2]; + outPtr[3] = reinterpret_cast<float *>(src+byteOfs)[3]; + break; + case NVRenderTextureFormats::RGB32F: + outPtr[0] = reinterpret_cast<float *>(src+byteOfs)[0]; + outPtr[1] = reinterpret_cast<float *>(src+byteOfs)[1]; + outPtr[2] = reinterpret_cast<float *>(src+byteOfs)[2]; + break; + + case NVRenderTextureFormats::RGBA16F: + /* + for ( NVU32 i = 0; i < 4; ++i ) + { + // NOTE : This only works on the assumption that we don't have any denormals, Infs or NaNs. + // Every pixel in our source image should be "regular" + NVU16 h = reinterpret_cast<NVU16 *>(src + byteOfs)[i]; + NVU32 sign = (h & 0x8000) << 16; + NVU32 exponent = (((((h & 0x7c00) >> 10) - 15) + 127) << 23); + NVU32 mantissa = ((h & 0x3ff) << 13); + NVU32 result = sign | exponent | mantissa; + + if (h == 0 || h == 0x8000) { result = 0; } // Special case for zero and negative zero + memcpy( reinterpret_cast<NVU32 *>(outPtr) + i, &result, 4 ); + }*/ + + for ( NVU32 i = 0; i < 2; i++ ) + { + // NOTE : This only works on the assumption that we don't have any denormals, Infs or NaNs. + // Every pixel in our source image should be "regular" + + NVU32 h1 = reinterpret_cast<NVU32 *>(src + byteOfs)[i]; + + for ( NVU8 j = 0; j < 2; j++ ) + { + NVU16 h = (h1 & (0x0000FFFF << j*16 )) >> j*16; + NVU32 sign = (h & 0x8000) << 16; + NVU32 exponent = (((((h & 0x7c00) >> 10) - 15) + 127) << 23); + NVU32 mantissa = ((h & 0x3ff) << 13); + NVU32 result = sign | exponent | mantissa; + + if (h == 0 || h == 0x8000) { result = 0; } // Special case for zero and negative zero + memcpy( reinterpret_cast<NVU32 *>(outPtr) + i*2 + j, &result, 4 ); + } + } + break; + + case NVRenderTextureFormats::R11G11B10: + // place holder + NV_ASSERT( false ); + break; + + default: + outPtr[0] = 0.0f; + outPtr[1] = 0.0f; + outPtr[2] = 0.0f; + outPtr[3] = 0.0f; + break; + } +} + +void __device__ encodeToPixel( float *inPtr, void *outPtr, NVU32 byteOfs, NVRenderTextureFormats::Enum inFmt, unsigned int noOfComponent ) +{ + NVU8 *dest = reinterpret_cast<NVU8 *>(outPtr); + switch(inFmt) + { + case NVRenderTextureFormats::Alpha8: + dest[byteOfs] = NVU8( inPtr[0] * 255.0f ); + break; + + case NVRenderTextureFormats::Luminance8: + case NVRenderTextureFormats::LuminanceAlpha8: + case NVRenderTextureFormats::R8: + case NVRenderTextureFormats::RG8: + case NVRenderTextureFormats::RGB8: + case NVRenderTextureFormats::RGBA8: + case NVRenderTextureFormats::SRGB8: + case NVRenderTextureFormats::SRGB8A8: + for ( NVU32 i = 0; i < noOfComponent; ++i ) + { + inPtr[i] = (inPtr[i] > 1.0f) ? 1.0f : inPtr[i]; + if (i < 3) + dest[byteOfs+i] = NVU8( powf( inPtr[i], 2.2f ) * 255.0f); + else + dest[byteOfs+i] = NVU8( inPtr[i] * 255.0f ); + } + break; + + case NVRenderTextureFormats::RGBA32F: + reinterpret_cast<float *>(dest+byteOfs)[0] = inPtr[0]; + reinterpret_cast<float *>(dest+byteOfs)[1] = inPtr[1]; + reinterpret_cast<float *>(dest+byteOfs)[2] = inPtr[2]; + reinterpret_cast<float *>(dest+byteOfs)[3] = inPtr[3]; + break; + case NVRenderTextureFormats::RGB32F: + reinterpret_cast<float *>(dest+byteOfs)[0] = inPtr[0]; + reinterpret_cast<float *>(dest+byteOfs)[1] = inPtr[1]; + reinterpret_cast<float *>(dest+byteOfs)[2] = inPtr[2]; + break; + + case NVRenderTextureFormats::RGBA16F: + for ( NVU32 i = 0; i < 4; ++i ) + { + // NOTE : This also has the limitation of not handling infs, NaNs and denormals, but it should be + // sufficient for our purposes. + if (inPtr[i] > 65519.0f) { inPtr[i] = 65519.0f; } + if (fabs(inPtr[i]) < 6.10352E-5f) { inPtr[i] = 0.0f; } + NVU32 f = reinterpret_cast<NVU32 *>(inPtr)[i]; + NVU32 sign = (f & 0x80000000) >> 16; + NVI32 exponent = (f & 0x7f800000) >> 23; + NVU32 mantissa = (f >> 13) & 0x3ff; + exponent = exponent - 112; + if (exponent > 31) { exponent = 31; } + if (exponent < 0) { exponent = 0; } + exponent = exponent << 10; + reinterpret_cast<NVU16 *>(dest + byteOfs)[i] = NVU16(sign | exponent | mantissa); + } + break; + + case NVRenderTextureFormats::R11G11B10: + // place holder + NV_ASSERT( false ); + break; + + default: + dest[byteOfs] = 0; + dest[byteOfs+1] = 0; + dest[byteOfs+2] = 0; + dest[byteOfs+3] = 0; + break; + } +} + +void __global__ Convert3To4Component( cudaTextureObject_t tex, float *d_outBuffer, Q3DStudio::INT32 dpitch, Q3DStudio::INT32 width, Q3DStudio::INT32 height ) +{ + float *dest = d_outBuffer; + + int x = threadIdx.x + blockIdx.x * blockDim.x; + int y = threadIdx.y + blockIdx.y * blockDim.y; + if ( x >= width || y >= height ) + return; + int inX = x * 3; + int outX = x * 4; + dest[outX + y * width * 4] = tex2D<float>(tex, inX, y); + dest[outX + y * width * 4 + 1] = tex2D<float>(tex, inX + 1, y); + dest[outX + y * width * 4 + 2] = tex2D<float>(tex, inX + 2, y); + dest[outX + y * width * 4 + 3] = 255 * 255; +} + +void __global__ ConvertData( void* d_InBuffer, NVRenderTextureFormats::Enum inFmt, int inSizeOfFormat, int inNoOfComponent, int inPitch, + void* d_OutBuffer, NVRenderTextureFormats::Enum outFmt, int outSizeOfFormat, int outNoOfComponent, int outPitch, int width, int height ) +{ + + int x = threadIdx.x + blockIdx.x * blockDim.x; + int y = threadIdx.y + blockIdx.y * blockDim.y; + if ( x >= width || y >= height ) + return; + float values[4]; + + decodeToFloat( d_InBuffer, (inPitch * y) + (x * inSizeOfFormat), values, inFmt, inNoOfComponent ); + encodeToPixel( values, d_OutBuffer, (outPitch * y) + (x * outSizeOfFormat), outFmt, outSizeOfFormat ); +} + +void __global__ CreateBsdfMipLevel( cudaTextureObject_t tex, void *d_curBuffer, void *d_prevBuffer, Q3DStudio::INT32 pitch, Q3DStudio::INT32 width, Q3DStudio::INT32 height, + nv::render::NVRenderTextureFormats::Enum inFormat, unsigned int sizeOfFormat ) +{ + float accumVal[4]; + //unsigned int sizeofFormat = getSizeofFormat(inFormat); + //__shared__ float dataBlock[ ]; //(32+4) * (32+4) * 12 + int x = threadIdx.x + blockIdx.x * blockDim.x; + int y = threadIdx.y + blockIdx.y * blockDim.y; + + if ( x >= (width > 2 ? width >> 1 : 1) || y >= (height > 2 ? height >> 1 : 1)) return; + + accumVal[0] = 0; accumVal[1] = 0; accumVal[2] = 0; accumVal[3] = 0; + + for ( int sy = -2; sy <= 2; ++sy ) + { + for ( int sx = -2; sx <= 2; ++sx ) + { + int sampleX = sx + (x << 1); + int sampleY = sy + (y << 1); + //getWrappedCoords(sampleX, sampleY, width, height); + // Cauchy filter (this is simply because it's the easiest to evaluate, and requires no complex + // functions). + float filterPdf = 1.f / ( 1.f + float(sx*sx + sy*sy)*2.f ); + // With FP HDR formats, we're not worried about intensity loss so much as unnecessary energy gain, + // whereas with LDR formats, the fear with a continuous normalization factor is that we'd lose + // intensity and saturation as well. + filterPdf /= sizeOfFormat >= 8 ? 4.71238898f : 4.5403446f; + //filterPdf /= 4.5403446f; // Discrete normalization factor + //filterPdf /= 4.71238898f; // Continuous normalization factor + //float curPix[4]; + sampleX = sampleX*4; + getWrappedCoords(sampleX, sampleY, width*4, height); + accumVal[0] += filterPdf * tex2D<float>(tex, sampleX, sampleY); + accumVal[1] += filterPdf * tex2D<float>(tex, sampleX + 1, sampleY); + accumVal[2] += filterPdf * tex2D<float>(tex, sampleX + 2, sampleY); + accumVal[3] += filterPdf * tex2D<float>(tex, sampleX + 3, sampleY); + } + } + + encodeToPixel(accumVal, d_curBuffer, y * pitch + x * sizeOfFormat, inFormat, sizeOfFormat); +} + +struct SMipTextureData +{ + void* data; + unsigned int dataSize; + unsigned int mipLevel; + unsigned int width; + unsigned int height; + NVRenderTextureFormats::Enum format; +}; + +__host__ void CUDABSDFMipMap::Build( void* inTextureData, int inTextureDataSize, NVRenderBackend::NVRenderBackendTextureObject inTextureHandle, NVRenderTextureFormats::Enum inFormat ) +{ + m_TextureHandle = inTextureHandle; + m_InternalFormat = inFormat; + m_SizeOfInternalFormat = NVRenderTextureFormats::getSizeofFormat( m_InternalFormat ); + m_InternalNoOfComponent = NVRenderTextureFormats::getNumberOfComponent( m_InternalFormat ); + + m_Texture2D.SetTextureData( NVDataRef<NVU8>( (NVU8*)inTextureData, inTextureDataSize ) + , 0 + , m_Width + , m_Height + , inFormat + , m_DestinationFormat ); + + size_t pitch; + float* d_inTextureData; + + cudaMallocPitch(&d_inTextureData, &pitch, m_Width * m_SizeOfInternalFormat, m_Height); CHECK_AND_HANDLE_CUDA_ERROR(); + CHECK_AND_HANDLE_CUDA_ERROR( cudaMemcpy2D( d_inTextureData, pitch, inTextureData, m_Width * m_SizeOfInternalFormat, m_Width * m_SizeOfInternalFormat, m_Height, cudaMemcpyHostToDevice ) ); + { + dim3 blockDim(16, 16, 1); + dim3 gridDim(ceil(m_Width / 16.0f), ceil(m_Height / 16.0f) ,1 ); + + //std::cerr << "if= " << m_InternalFormat << " sizeOut= " << m_SizeOfInternalFormat << " numOfIntComp" << m_InternalNoOfComponent << " pitch= " << pitch << " destFormat= " << m_DestinationFormat << " sizeFormat= " << m_SizeOfFormat << " numOfComp= " << m_NoOfComponent << " Pitch0=" << m_Pitches[0] << std::endl; + //NVLogWarn("cuda", "%i %i %i %i %i %i %i %i\n",(int)m_InternalFormat ,m_SizeOfInternalFormat ,m_InternalNoOfComponent , pitch, (int)m_DestinationFormat, m_SizeOfFormat, m_NoOfComponent ,m_Pitches[0]); + ConvertData<<<gridDim, blockDim>>>( d_inTextureData, m_InternalFormat, m_SizeOfInternalFormat, m_InternalNoOfComponent, pitch, + md_MipMapsData[0], m_DestinationFormat, m_SizeOfFormat, m_NoOfComponent, m_Pitches[0], m_Width, m_Height ); + } + cudaFree(d_inTextureData); + + int curWidth = m_Width; + int curHeight = m_Height; + + cudaTextureObject_t* tex; + tex = new cudaTextureObject_t[m_MaxMipMapLevel]; + for ( int idx = 1; idx <= m_MaxMipMapLevel; ++idx ) + { + tex[idx-1] = -1; + dim3 blockDim(16, 16, 1); + dim3 gridDim(ceil(curWidth / 32.0f), ceil(curHeight / 32.0f) ,1 ); + + cudaResourceDesc resDesc; + memset(&resDesc, 0, sizeof(resDesc)); + resDesc.res.pitch2D.desc.f = cudaChannelFormatKindFloat; + resDesc.res.pitch2D.desc.x = m_SizeOfFormat / m_NoOfComponent * 8; // bits per channel + resDesc.resType = cudaResourceTypePitch2D; + resDesc.res.pitch2D.devPtr = (char*)(md_MipMapsData[idx-1]); + resDesc.res.pitch2D.height = curHeight; + resDesc.res.pitch2D.width = curWidth * m_NoOfComponent; + resDesc.res.pitch2D.pitchInBytes = m_Pitches[idx-1];// aligned to texturePitchAlignment + + cudaTextureDesc texDesc; + memset(&texDesc, 0, sizeof(texDesc)); + texDesc.addressMode[0] = cudaAddressModeWrap; + texDesc.addressMode[1] = cudaAddressModeWrap; + texDesc.readMode = cudaReadModeElementType; + //texDesc.normalizedCoords = 1; + + + CHECK_AND_HANDLE_CUDA_ERROR( cudaCreateTextureObject( &tex[idx-1], &resDesc, &texDesc, NULL ) ); + CreateBsdfMipLevel<<<gridDim, blockDim>>>( tex[idx-1], (reinterpret_cast<NVU8 *>(md_MipMapsData[idx])), (reinterpret_cast<NVU8 *>(md_MipMapsData[idx-1])), m_Pitches[idx], curWidth, curHeight, m_DestinationFormat, m_SizeOfFormat ); + + curWidth = curWidth > 2 ? curWidth >> 1 : 1; + curHeight = curHeight > 2 ? curHeight >> 1 : 1; + } + + CHECK_AND_HANDLE_CUDA_ERROR( cudaDeviceSynchronize(); ) + BindTexture(); + TransferTexture(); + for (int idx = 0; idx < m_MaxMipMapLevel;++idx ) + cudaDestroyTextureObject(tex[idx]); +// CHECK_AND_HANDLE_CUDA_ERROR( cudaDeviceReset(); ) + CHECK_AND_HANDLE_CUDA_ERROR( cudaDeviceSynchronize(); ) + + //NV_FREE( m_Foundation.getAllocator(), inTextureData ); + +} diff --git a/src/hdr/MipmapBSDF.h b/src/hdr/MipmapBSDF.h new file mode 100644 index 0000000..be8f136 --- /dev/null +++ b/src/hdr/MipmapBSDF.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef MIPMAPBSDF_H +#define MIPMAPBSDF_H +#include "foundation/Qt3DSVec3.h" +#include "foundation/Qt3DSSimpleTypes.h" +#include "foundation/Qt3DSPerfTimer.h" +#include "foundation/Qt3DSAtomic.h" +#include "render/Qt3DSRenderBaseTypes.h" +#include "render/backends/Qt3DSRenderBackend.h" +#include "render/Qt3DSRenderTexture2D.h" +#include "render/backends/gl/Qt3DSOpenGLUtil.h" + +#include "Qt3DSRenderLoadedTexture.h" + +#include "Qt3DSTypes.h" +#ifdef _LINUXPLATFORM +#define __declspec(dllexport) +#define __cdecl + +#endif +using namespace qt3ds::render; + +class BSDFMipMap : public NVRefCounted +{ +public: + BSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture, NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd); + virtual ~BSDFMipMap(); + + virtual void Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject inTextureHandle, + NVRenderTextureFormats::Enum inFormat) = 0; + static BSDFMipMap *Create(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture, + NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd); + +protected: + volatile QT3DSI32 mRefCount; ///< reference count + NVFoundationBase &m_Foundation; ///< Foundation class for allocations and other base things + + NVRenderTexture2D &m_Texture2D; + NVRenderTextureFormats::Enum m_InternalFormat; + NVRenderTextureFormats::Enum m_DestinationFormat; + int m_Width; + int m_Height; + int m_MaxMipMapLevel; + int m_SizeOfFormat; + int m_SizeOfInternalFormat; + int m_InternalNoOfComponent; + int m_NoOfComponent; + NVRenderContext *m_NVRenderContext; +}; + +class BasicBSDFMipMap : public BSDFMipMap +{ +public: + BasicBSDFMipMap(NVRenderContext *inNVRenderContext, int inWidth, int inHeight, + NVRenderTexture2D &inTexture, NVRenderTextureFormats::Enum inDestFormat, + qt3ds::NVFoundationBase &inFnd); + + void Build(void *inTextureData, int inTextureDataSize, + NVRenderBackend::NVRenderBackendTextureObject inTextureHandle, + NVRenderTextureFormats::Enum inFormat); + + STextureData CreateBsdfMipLevel(STextureData &inCurMipLevel, STextureData &inPrevMipLevel, + int width, int height); //, IPerfTimer& inPerfTimer ); + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation); + + int wrapMod(int a, int base); + void getWrappedCoords(int &sX, int &sY, int width, int height); + NVRenderBackend::NVRenderBackendTextureObject m_TextureHandle; +}; + +#endif |