Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -32,4 +32,3 @@ Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-d
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

View File

@@ -37,14 +37,12 @@
Look into the bindlessTexture_kernel.cu file for most relevant code.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <helper_gl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#if defined(__APPLE__) || defined(MACOSX)
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include <GLUT/glut.h>
@@ -55,31 +53,31 @@
#include <GL/freeglut.h>
#endif
#include <cuda_gl_interop.h>
#include <helper_functions.h>
#include "bindlessTexture.h"
#include <helper_functions.h>
#include <cuda_gl_interop.h>
#define MAX_EPSILON_ERROR 5.0f
#define THRESHOLD 0.15f
#define THRESHOLD 0.15f
const char *sSDKsample = "CUDA bindlessTexture";
const char *imageFilenames[] = {
"flower.ppm", "person.ppm", "sponge.ppm",
"flower.ppm",
"person.ppm",
"sponge.ppm",
};
const cudaExtent atlasSize = make_cudaExtent(4, 4, 0);
const dim3 windowSize(512, 512);
const dim3 windowBlockSize(16, 16, 1);
const dim3 windowGridSize(windowSize.x / windowBlockSize.x,
windowSize.y / windowBlockSize.y);
const dim3 windowSize(512, 512);
const dim3 windowBlockSize(16, 16, 1);
const dim3 windowGridSize(windowSize.x / windowBlockSize.x, windowSize.y / windowBlockSize.y);
float lod = 0.5; // texture mip map level
float lod = 0.5; // texture mip map level
GLuint pbo; // OpenGL pixel buffer object
struct cudaGraphicsResource *cuda_pbo_resource =
NULL; // CUDA Graphics Resource (to transfer PBO)
GLuint pbo; // OpenGL pixel buffer object
struct cudaGraphicsResource *cuda_pbo_resource = NULL; // CUDA Graphics Resource (to transfer PBO)
bool animate = true;
@@ -88,330 +86,335 @@ StopWatchInterface *timer = NULL;
uint *d_output = NULL;
// Auto-Verification Code
const int frameCheckNumber = 4;
int fpsCount = 0; // FPS count for averaging
int fpsLimit = 1; // FPS limit for sampling
int g_Index = 0;
unsigned int frameCount = 0;
unsigned int g_TotalErrors = 0;
const int frameCheckNumber = 4;
int fpsCount = 0; // FPS count for averaging
int fpsLimit = 1; // FPS limit for sampling
int g_Index = 0;
unsigned int frameCount = 0;
unsigned int g_TotalErrors = 0;
int *pArgc = NULL;
int *pArgc = NULL;
char **pArgv = NULL;
extern "C" void initAtlasAndImages(const Image *images, size_t numImages,
cudaExtent atlasSize);
extern "C" void initAtlasAndImages(const Image *images, size_t numImages, cudaExtent atlasSize);
extern "C" void deinitAtlasAndImages();
extern "C" void randomizeAtlas();
extern "C" void renderAtlasImage(dim3 gridSize, dim3 blockSize, uint *d_output,
uint imageW, uint imageH, float lod);
extern "C" void renderAtlasImage(dim3 gridSize, dim3 blockSize, uint *d_output, uint imageW, uint imageH, float lod);
void computeFPS() {
frameCount++;
fpsCount++;
void computeFPS()
{
frameCount++;
fpsCount++;
if (fpsCount == fpsLimit) {
char fps[256];
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
sprintf(fps, "%s: %3.1f fps", sSDKsample, ifps);
if (fpsCount == fpsLimit) {
char fps[256];
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
sprintf(fps, "%s: %3.1f fps", sSDKsample, ifps);
glutSetWindowTitle(fps);
fpsCount = 0;
glutSetWindowTitle(fps);
fpsCount = 0;
fpsLimit = (int)MAX(1.0f, ifps);
sdkResetTimer(&timer);
}
fpsLimit = (int)MAX(1.0f, ifps);
sdkResetTimer(&timer);
}
}
// render image using CUDA
void render() {
// map PBO to get CUDA device pointer
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
(void **)&d_output, &num_bytes, cuda_pbo_resource));
void render()
{
// map PBO to get CUDA device pointer
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&d_output, &num_bytes, cuda_pbo_resource));
// call CUDA kernel, writing results to PBO
renderAtlasImage(windowGridSize, windowBlockSize, d_output, windowSize.x,
windowSize.y, lod);
// call CUDA kernel, writing results to PBO
renderAtlasImage(windowGridSize, windowBlockSize, d_output, windowSize.x, windowSize.y, lod);
getLastCudaError("render_kernel failed");
getLastCudaError("render_kernel failed");
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
}
// display results using OpenGL (called by GLUT)
void display() {
sdkStartTimer(&timer);
void display()
{
sdkStartTimer(&timer);
render();
render();
// display results
glClear(GL_COLOR_BUFFER_BIT);
// display results
glClear(GL_COLOR_BUFFER_BIT);
// draw image from PBO
glDisable(GL_DEPTH_TEST);
glRasterPos2i(0, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
// draw image from PBO
glDisable(GL_DEPTH_TEST);
glRasterPos2i(0, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glutSwapBuffers();
glutReportErrors();
glutSwapBuffers();
glutReportErrors();
sdkStopTimer(&timer);
computeFPS();
sdkStopTimer(&timer);
computeFPS();
}
void idle() {
if (animate) {
lod += 0.02f;
glutPostRedisplay();
}
void idle()
{
if (animate) {
lod += 0.02f;
glutPostRedisplay();
}
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
#if defined(__APPLE__) || defined(MACOSX)
exit(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
#else
glutDestroyWindow(glutGetWindow());
return;
glutDestroyWindow(glutGetWindow());
return;
#endif
break;
break;
case '=':
case '+':
lod += 0.25f;
break;
lod += 0.25f;
break;
case '-':
lod -= 0.25f;
break;
lod -= 0.25f;
break;
case 'r':
randomizeAtlas();
break;
randomizeAtlas();
break;
case ' ':
animate = !animate;
lod = 0.0f;
break;
animate = !animate;
lod = 0.0f;
break;
default:
break;
}
break;
}
glutPostRedisplay();
glutPostRedisplay();
}
void reshape(int x, int y) {
glViewport(0, 0, x, y);
void reshape(int x, int y)
{
glViewport(0, 0, x, y);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
}
// Global cleanup function
// Shared by both GL and non-GL code paths
void cleanup() {
sdkDeleteTimer(&timer);
void cleanup()
{
sdkDeleteTimer(&timer);
// unregister this buffer object from CUDA C
if (cuda_pbo_resource) {
cudaGraphicsUnregisterResource(cuda_pbo_resource);
glDeleteBuffers(1, &pbo);
}
// unregister this buffer object from CUDA C
if (cuda_pbo_resource) {
cudaGraphicsUnregisterResource(cuda_pbo_resource);
glDeleteBuffers(1, &pbo);
}
}
void cleanup_all() {
cleanup();
deinitAtlasAndImages();
void cleanup_all()
{
cleanup();
deinitAtlasAndImages();
}
void initGLBuffers() {
// create pixel buffer object
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB,
windowSize.x * windowSize.y * sizeof(GLubyte) * 4, 0,
GL_STREAM_DRAW_ARB);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
void initGLBuffers()
{
// create pixel buffer object
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, windowSize.x * windowSize.y * sizeof(GLubyte) * 4, 0, GL_STREAM_DRAW_ARB);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
// register this buffer object with CUDA
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
&cuda_pbo_resource, pbo, cudaGraphicsMapFlagsWriteDiscard));
// register this buffer object with CUDA
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, pbo, cudaGraphicsMapFlagsWriteDiscard));
}
// Load raw data from disk
uchar *loadRawFile(const char *filename, size_t size) {
FILE *fp = fopen(filename, "rb");
uchar *loadRawFile(const char *filename, size_t size)
{
FILE *fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Error opening file '%s'\n", filename);
return 0;
}
uchar *data = (uchar *)malloc(size);
size_t read = fread(data, 1, size, fp);
fclose(fp);
printf("Read '%s', %zu bytes\n", filename, read);
return data;
}
void initGL(int *argc, char **argv) {
// initialize GLUT callback functions
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(windowSize.x, windowSize.y);
glutCreateWindow(sSDKsample);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
if (!isGLVersionSupported(2, 0) ||
!areGLExtensionsSupported("GL_ARB_pixel_buffer_object")) {
fprintf(stderr, "Required OpenGL extensions are missing.");
exit(EXIT_FAILURE);
}
}
void runAutoTest(const char *ref_file, char *exec_path) {
size_t windowBytes = windowSize.x * windowSize.y * sizeof(GLubyte) * 4;
checkCudaErrors(cudaMalloc((void **)&d_output, windowBytes));
// render the volumeData
renderAtlasImage(windowGridSize, windowBlockSize, d_output, windowSize.x,
windowSize.y, lod);
checkCudaErrors(cudaDeviceSynchronize());
getLastCudaError("render_kernel failed");
void *h_output = malloc(windowBytes);
checkCudaErrors(
cudaMemcpy(h_output, d_output, windowBytes, cudaMemcpyDeviceToHost));
sdkDumpBin(h_output, (unsigned int)windowBytes, "bindlessTexture.bin");
bool bTestResult = sdkCompareBin2BinFloat(
"bindlessTexture.bin", sdkFindFilePath(ref_file, exec_path),
windowSize.x * windowSize.y, MAX_EPSILON_ERROR, THRESHOLD, exec_path);
checkCudaErrors(cudaFree(d_output));
free(h_output);
deinitAtlasAndImages();
sdkStopTimer(&timer);
sdkDeleteTimer(&timer);
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
void loadImageData(const char *exe_path) {
std::vector<Image> images;
for (size_t i = 0; i < sizeof(imageFilenames) / sizeof(imageFilenames[0]);
i++) {
unsigned int imgWidth = 0;
unsigned int imgHeight = 0;
uchar *imgData = NULL;
const char *imgPath = 0;
const char *imgFilename = imageFilenames[i];
if (exe_path) {
imgPath = sdkFindFilePath(imgFilename, exe_path);
if (!fp) {
fprintf(stderr, "Error opening file '%s'\n", filename);
return 0;
}
if (imgPath == 0) {
printf("Error finding image file '%s'\n", imgFilename);
exit(EXIT_FAILURE);
uchar *data = (uchar *)malloc(size);
size_t read = fread(data, 1, size, fp);
fclose(fp);
printf("Read '%s', %zu bytes\n", filename, read);
return data;
}
void initGL(int *argc, char **argv)
{
// initialize GLUT callback functions
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(windowSize.x, windowSize.y);
glutCreateWindow(sSDKsample);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
if (!isGLVersionSupported(2, 0) || !areGLExtensionsSupported("GL_ARB_pixel_buffer_object")) {
fprintf(stderr, "Required OpenGL extensions are missing.");
exit(EXIT_FAILURE);
}
}
void runAutoTest(const char *ref_file, char *exec_path)
{
size_t windowBytes = windowSize.x * windowSize.y * sizeof(GLubyte) * 4;
checkCudaErrors(cudaMalloc((void **)&d_output, windowBytes));
// render the volumeData
renderAtlasImage(windowGridSize, windowBlockSize, d_output, windowSize.x, windowSize.y, lod);
checkCudaErrors(cudaDeviceSynchronize());
getLastCudaError("render_kernel failed");
void *h_output = malloc(windowBytes);
checkCudaErrors(cudaMemcpy(h_output, d_output, windowBytes, cudaMemcpyDeviceToHost));
sdkDumpBin(h_output, (unsigned int)windowBytes, "bindlessTexture.bin");
bool bTestResult = sdkCompareBin2BinFloat("bindlessTexture.bin",
sdkFindFilePath(ref_file, exec_path),
windowSize.x * windowSize.y,
MAX_EPSILON_ERROR,
THRESHOLD,
exec_path);
checkCudaErrors(cudaFree(d_output));
free(h_output);
deinitAtlasAndImages();
sdkStopTimer(&timer);
sdkDeleteTimer(&timer);
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
void loadImageData(const char *exe_path)
{
std::vector<Image> images;
for (size_t i = 0; i < sizeof(imageFilenames) / sizeof(imageFilenames[0]); i++) {
unsigned int imgWidth = 0;
unsigned int imgHeight = 0;
uchar *imgData = NULL;
const char *imgPath = 0;
const char *imgFilename = imageFilenames[i];
if (exe_path) {
imgPath = sdkFindFilePath(imgFilename, exe_path);
}
if (imgPath == 0) {
printf("Error finding image file '%s'\n", imgFilename);
exit(EXIT_FAILURE);
}
sdkLoadPPM4(imgPath, (unsigned char **)&imgData, &imgWidth, &imgHeight);
if (!imgData) {
printf("Error opening file '%s'\n", imgPath);
exit(EXIT_FAILURE);
}
printf("Loaded '%s', %d x %d pixels\n", imgPath, imgWidth, imgHeight);
checkHost(imgWidth > 1);
checkHost(imgHeight > 1);
Image img;
img.size = make_cudaExtent(imgWidth, imgHeight, 0);
img.h_data = imgData;
images.push_back(img);
}
sdkLoadPPM4(imgPath, (unsigned char **)&imgData, &imgWidth, &imgHeight);
if (!imgData) {
printf("Error opening file '%s'\n", imgPath);
exit(EXIT_FAILURE);
}
printf("Loaded '%s', %d x %d pixels\n", imgPath, imgWidth, imgHeight);
checkHost(imgWidth > 1);
checkHost(imgHeight > 1);
Image img;
img.size = make_cudaExtent(imgWidth, imgHeight, 0);
img.h_data = imgData;
images.push_back(img);
}
initAtlasAndImages(&images[0], images.size(), atlasSize);
initAtlasAndImages(&images[0], images.size(), atlasSize);
}
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
sdkCreateTimer(&timer);
int main(int argc, char **argv)
{
sdkCreateTimer(&timer);
pArgc = &argc;
pArgv = argv;
pArgc = &argc;
pArgv = argv;
char *ref_file = NULL;
char *ref_file = NULL;
#if defined(__linux__)
setenv("DISPLAY", ":0", 0);
setenv("DISPLAY", ":0", 0);
#endif
printf("%s Starting...\n\n", sSDKsample);
printf("%s Starting...\n\n", sSDKsample);
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
fpsLimit = frameCheckNumber;
getCmdLineArgumentString(argc, (const char **)argv, "file", &ref_file);
}
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
fpsLimit = frameCheckNumber;
getCmdLineArgumentString(argc, (const char **)argv, "file", &ref_file);
}
srand(15234);
srand(15234);
// use command-line specified CUDA device, otherwise use device with highest
// Gflops/s
findCudaDevice(argc, (const char **)argv);
// use command-line specified CUDA device, otherwise use device with highest
// Gflops/s
findCudaDevice(argc, (const char **)argv);
if (!ref_file) {
initGL(&argc, argv);
if (!ref_file) {
initGL(&argc, argv);
// OpenGL buffers
initGLBuffers();
}
// OpenGL buffers
initGLBuffers();
}
if (!checkCudaCapabilities(3, 0)) {
cleanup();
if (!checkCudaCapabilities(3, 0)) {
cleanup();
exit(EXIT_WAIVED);
}
exit(EXIT_WAIVED);
}
loadImageData(argv[0]);
loadImageData(argv[0]);
if (ref_file) {
runAutoTest(ref_file, argv[0]);
}
if (ref_file) {
runAutoTest(ref_file, argv[0]);
}
printf(
"Press space to toggle animation\n"
"Press '+' and '-' to change lod level\n"
"Press 'r' to randomize virtual atlas\n");
printf("Press space to toggle animation\n"
"Press '+' and '-' to change lod level\n"
"Press 'r' to randomize virtual atlas\n");
#if defined(__APPLE__) || defined(MACOSX)
atexit(cleanup_all);
atexit(cleanup_all);
#else
glutCloseFunc(cleanup_all);
glutCloseFunc(cleanup_all);
#endif
glutMainLoop();
glutMainLoop();
}

View File

@@ -29,39 +29,38 @@
#define _BINDLESSTEXTURE_CU_
// includes, cuda
#include <vector_types.h>
#include <cuda_runtime.h>
#include <vector_types.h>
// CUDA utilities and system includes
#include <helper_cuda.h>
#include <vector_types.h>
typedef unsigned int uint;
typedef unsigned int uint;
typedef unsigned char uchar;
#pragma pack(push, 4)
struct Image {
void *h_data;
cudaExtent size;
cudaResourceType type;
cudaArray_t dataArray;
cudaMipmappedArray_t mipmapArray;
cudaTextureObject_t textureObject;
struct Image
{
void *h_data;
cudaExtent size;
cudaResourceType type;
cudaArray_t dataArray;
cudaMipmappedArray_t mipmapArray;
cudaTextureObject_t textureObject;
Image() { memset(this, 0, sizeof(Image)); }
Image() { memset(this, 0, sizeof(Image)); }
};
#pragma pack(pop)
inline void _checkHost(bool test, const char *condition, const char *file,
int line, const char *func) {
if (!test) {
fprintf(stderr, "HOST error at %s:%d (%s) \"%s\" \n", file, line, condition,
func);
exit(EXIT_FAILURE);
}
inline void _checkHost(bool test, const char *condition, const char *file, int line, const char *func)
{
if (!test) {
fprintf(stderr, "HOST error at %s:%d (%s) \"%s\" \n", file, line, condition, func);
exit(EXIT_FAILURE);
}
}
#define checkHost(condition) \
_checkHost(condition, #condition, __FILE__, __LINE__, __FUNCTION__)
#define checkHost(condition) _checkHost(condition, #condition, __FILE__, __LINE__, __FUNCTION__)
#endif

View File

@@ -41,26 +41,24 @@
#ifndef _BINDLESSTEXTURE_KERNEL_CU_
#define _BINDLESSTEXTURE_KERNEL_CU_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <helper_cuda.h>
#include <helper_math.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "bindlessTexture.h"
// set this to just see the mipmap chain of first image
//#define SHOW_MIPMAPS
// #define SHOW_MIPMAPS
// local references to resources
Image atlasImage;
Image atlasImage;
std::vector<Image> contentImages;
float highestLod = 1.0f;
float highestLod = 1.0f;
#ifndef MAX
#define MAX(a, b) ((a > b) ? a : b)
@@ -68,22 +66,21 @@ float highestLod = 1.0f;
//////////////////////////////////////////////////////////////////////////
__host__ __device__ __inline__ uint2 encodeTextureObject(
cudaTextureObject_t obj) {
return make_uint2((uint)(obj & 0xFFFFFFFF), (uint)(obj >> 32));
__host__ __device__ __inline__ uint2 encodeTextureObject(cudaTextureObject_t obj)
{
return make_uint2((uint)(obj & 0xFFFFFFFF), (uint)(obj >> 32));
}
__host__ __device__ __inline__ cudaTextureObject_t decodeTextureObject(
uint2 obj) {
return (((cudaTextureObject_t)obj.x) | ((cudaTextureObject_t)obj.y) << 32);
__host__ __device__ __inline__ cudaTextureObject_t decodeTextureObject(uint2 obj)
{
return (((cudaTextureObject_t)obj.x) | ((cudaTextureObject_t)obj.y) << 32);
}
__device__ __inline__ float4 to_float4(uchar4 vec) {
return make_float4(vec.x, vec.y, vec.z, vec.w);
}
__device__ __inline__ float4 to_float4(uchar4 vec) { return make_float4(vec.x, vec.y, vec.z, vec.w); }
__device__ __inline__ uchar4 to_uchar4(float4 vec) {
return make_uchar4((uchar)vec.x, (uchar)vec.y, (uchar)vec.z, (uchar)vec.w);
__device__ __inline__ uchar4 to_uchar4(float4 vec)
{
return make_uchar4((uchar)vec.x, (uchar)vec.y, (uchar)vec.z, (uchar)vec.w);
}
//////////////////////////////////////////////////////////////////////////
@@ -92,48 +89,46 @@ __device__ __inline__ uchar4 to_uchar4(float4 vec) {
// the atlas texture stores the 64 bit cudaTextureObjects
// we use it for "virtual" texturing
__global__ void d_render(uchar4 *d_output, uint imageW, uint imageH, float lod,
cudaTextureObject_t atlasTexture) {
uint x = blockIdx.x * blockDim.x + threadIdx.x;
uint y = blockIdx.y * blockDim.y + threadIdx.y;
__global__ void d_render(uchar4 *d_output, uint imageW, uint imageH, float lod, cudaTextureObject_t atlasTexture)
{
uint x = blockIdx.x * blockDim.x + threadIdx.x;
uint y = blockIdx.y * blockDim.y + threadIdx.y;
float u = x / (float)imageW;
float v = y / (float)imageH;
float u = x / (float)imageW;
float v = y / (float)imageH;
if ((x < imageW) && (y < imageH)) {
// read from 2D atlas texture and decode texture object
uint2 texCoded = tex2D<uint2>(atlasTexture, u, v);
cudaTextureObject_t tex = decodeTextureObject(texCoded);
if ((x < imageW) && (y < imageH)) {
// read from 2D atlas texture and decode texture object
uint2 texCoded = tex2D<uint2>(atlasTexture, u, v);
cudaTextureObject_t tex = decodeTextureObject(texCoded);
// read from cuda texture object, use template to specify what data will be
// returned. tex2DLod allows us to pass the lod (mip map level) directly.
// There is other functions with CUDA 5, e.g. tex2DGrad, that allow you
// to pass derivatives to perform automatic mipmap/anisotropic filtering.
float4 color = tex2DLod<float4>(tex, u, 1 - v, lod);
// In our sample tex is always valid, but for something like your own
// sparse texturing you would need to make sure to handle the zero case.
// read from cuda texture object, use template to specify what data will be
// returned. tex2DLod allows us to pass the lod (mip map level) directly.
// There is other functions with CUDA 5, e.g. tex2DGrad, that allow you
// to pass derivatives to perform automatic mipmap/anisotropic filtering.
float4 color = tex2DLod<float4>(tex, u, 1 - v, lod);
// In our sample tex is always valid, but for something like your own
// sparse texturing you would need to make sure to handle the zero case.
// write output color
uint i = y * imageW + x;
d_output[i] = to_uchar4(color * 255.0);
}
// write output color
uint i = y * imageW + x;
d_output[i] = to_uchar4(color * 255.0);
}
}
extern "C" void renderAtlasImage(dim3 gridSize, dim3 blockSize,
uchar4 *d_output, uint imageW, uint imageH,
float lod) {
// psuedo animate lod
lod = fmodf(lod, highestLod * 2);
lod = highestLod - fabs(lod - highestLod);
extern "C" void renderAtlasImage(dim3 gridSize, dim3 blockSize, uchar4 *d_output, uint imageW, uint imageH, float lod)
{
// psuedo animate lod
lod = fmodf(lod, highestLod * 2);
lod = highestLod - fabs(lod - highestLod);
#ifdef SHOW_MIPMAPS
lod = 0.0f;
lod = 0.0f;
#endif
d_render<<<gridSize, blockSize>>>(d_output, imageW, imageH, lod,
atlasImage.textureObject);
d_render<<<gridSize, blockSize>>>(d_output, imageW, imageH, lod, atlasImage.textureObject);
checkCudaErrors(cudaGetLastError());
checkCudaErrors(cudaGetLastError());
}
//////////////////////////////////////////////////////////////////////////
@@ -143,287 +138,278 @@ extern "C" void renderAtlasImage(dim3 gridSize, dim3 blockSize,
// global binding points anymore. We can directly pass them as function
// arguments.
__global__ void d_mipmap(cudaSurfaceObject_t mipOutput,
cudaTextureObject_t mipInput, uint imageW,
uint imageH) {
uint x = blockIdx.x * blockDim.x + threadIdx.x;
uint y = blockIdx.y * blockDim.y + threadIdx.y;
__global__ void d_mipmap(cudaSurfaceObject_t mipOutput, cudaTextureObject_t mipInput, uint imageW, uint imageH)
{
uint x = blockIdx.x * blockDim.x + threadIdx.x;
uint y = blockIdx.y * blockDim.y + threadIdx.y;
float px = 1.0 / float(imageW);
float py = 1.0 / float(imageH);
float px = 1.0 / float(imageW);
float py = 1.0 / float(imageH);
if ((x < imageW) && (y < imageH)) {
// take the average of 4 samples
if ((x < imageW) && (y < imageH)) {
// take the average of 4 samples
// we are using the normalized access to make sure non-power-of-two textures
// behave well when downsized.
float4 color = (tex2D<float4>(mipInput, (x + 0) * px, (y + 0) * py)) +
(tex2D<float4>(mipInput, (x + 1) * px, (y + 0) * py)) +
(tex2D<float4>(mipInput, (x + 1) * px, (y + 1) * py)) +
(tex2D<float4>(mipInput, (x + 0) * px, (y + 1) * py));
// we are using the normalized access to make sure non-power-of-two textures
// behave well when downsized.
float4 color = (tex2D<float4>(mipInput, (x + 0) * px, (y + 0) * py))
+ (tex2D<float4>(mipInput, (x + 1) * px, (y + 0) * py))
+ (tex2D<float4>(mipInput, (x + 1) * px, (y + 1) * py))
+ (tex2D<float4>(mipInput, (x + 0) * px, (y + 1) * py));
color /= 4.0;
color *= 255.0;
color = fminf(color, make_float4(255.0));
color /= 4.0;
color *= 255.0;
color = fminf(color, make_float4(255.0));
surf2Dwrite(to_uchar4(color), mipOutput, x * sizeof(uchar4), y);
}
surf2Dwrite(to_uchar4(color), mipOutput, x * sizeof(uchar4), y);
}
}
void generateMipMaps(cudaMipmappedArray_t mipmapArray, cudaExtent size) {
size_t width = size.width;
size_t height = size.height;
void generateMipMaps(cudaMipmappedArray_t mipmapArray, cudaExtent size)
{
size_t width = size.width;
size_t height = size.height;
#ifdef SHOW_MIPMAPS
cudaArray_t levelFirst;
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelFirst, mipmapArray, 0));
cudaArray_t levelFirst;
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelFirst, mipmapArray, 0));
#endif
uint level = 0;
uint level = 0;
while (width != 1 || height != 1) {
width /= 2;
width = MAX((size_t)1, width);
height /= 2;
height = MAX((size_t)1, height);
while (width != 1 || height != 1) {
width /= 2;
width = MAX((size_t)1, width);
height /= 2;
height = MAX((size_t)1, height);
cudaArray_t levelFrom;
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelFrom, mipmapArray, level));
cudaArray_t levelTo;
checkCudaErrors(
cudaGetMipmappedArrayLevel(&levelTo, mipmapArray, level + 1));
cudaArray_t levelFrom;
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelFrom, mipmapArray, level));
cudaArray_t levelTo;
checkCudaErrors(cudaGetMipmappedArrayLevel(&levelTo, mipmapArray, level + 1));
cudaExtent levelToSize;
checkCudaErrors(cudaArrayGetInfo(NULL, &levelToSize, NULL, levelTo));
checkHost(levelToSize.width == width);
checkHost(levelToSize.height == height);
checkHost(levelToSize.depth == 0);
cudaExtent levelToSize;
checkCudaErrors(cudaArrayGetInfo(NULL, &levelToSize, NULL, levelTo));
checkHost(levelToSize.width == width);
checkHost(levelToSize.height == height);
checkHost(levelToSize.depth == 0);
// generate texture object for reading
cudaTextureObject_t texInput;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
// generate texture object for reading
cudaTextureObject_t texInput;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = levelFrom;
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = levelFrom;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = 1;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.normalizedCoords = 1;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[2] = cudaAddressModeClamp;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[2] = cudaAddressModeClamp;
texDescr.readMode = cudaReadModeNormalizedFloat;
texDescr.readMode = cudaReadModeNormalizedFloat;
checkCudaErrors(
cudaCreateTextureObject(&texInput, &texRes, &texDescr, NULL));
checkCudaErrors(cudaCreateTextureObject(&texInput, &texRes, &texDescr, NULL));
// generate surface object for writing
// generate surface object for writing
cudaSurfaceObject_t surfOutput;
cudaResourceDesc surfRes;
memset(&surfRes, 0, sizeof(cudaResourceDesc));
surfRes.resType = cudaResourceTypeArray;
surfRes.res.array.array = levelTo;
cudaSurfaceObject_t surfOutput;
cudaResourceDesc surfRes;
memset(&surfRes, 0, sizeof(cudaResourceDesc));
surfRes.resType = cudaResourceTypeArray;
surfRes.res.array.array = levelTo;
checkCudaErrors(cudaCreateSurfaceObject(&surfOutput, &surfRes));
checkCudaErrors(cudaCreateSurfaceObject(&surfOutput, &surfRes));
// run mipmap kernel
dim3 blockSize(16, 16, 1);
dim3 gridSize(((uint)width + blockSize.x - 1) / blockSize.x,
((uint)height + blockSize.y - 1) / blockSize.y, 1);
// run mipmap kernel
dim3 blockSize(16, 16, 1);
dim3 gridSize(((uint)width + blockSize.x - 1) / blockSize.x, ((uint)height + blockSize.y - 1) / blockSize.y, 1);
d_mipmap<<<gridSize, blockSize>>>(surfOutput, texInput, (uint)width,
(uint)height);
d_mipmap<<<gridSize, blockSize>>>(surfOutput, texInput, (uint)width, (uint)height);
checkCudaErrors(cudaDeviceSynchronize());
checkCudaErrors(cudaGetLastError());
checkCudaErrors(cudaDeviceSynchronize());
checkCudaErrors(cudaGetLastError());
checkCudaErrors(cudaDestroySurfaceObject(surfOutput));
checkCudaErrors(cudaDestroySurfaceObject(surfOutput));
checkCudaErrors(cudaDestroyTextureObject(texInput));
checkCudaErrors(cudaDestroyTextureObject(texInput));
#ifdef SHOW_MIPMAPS
// we blit the current mipmap back into first level
cudaMemcpy3DParms copyParams = {0};
copyParams.dstArray = levelFirst;
copyParams.srcArray = levelTo;
copyParams.extent = make_cudaExtent(width, height, 1);
copyParams.kind = cudaMemcpyDeviceToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
// we blit the current mipmap back into first level
cudaMemcpy3DParms copyParams = {0};
copyParams.dstArray = levelFirst;
copyParams.srcArray = levelTo;
copyParams.extent = make_cudaExtent(width, height, 1);
copyParams.kind = cudaMemcpyDeviceToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
#endif
level++;
}
level++;
}
}
uint getMipMapLevels(cudaExtent size) {
size_t sz = MAX(MAX(size.width, size.height), size.depth);
uint getMipMapLevels(cudaExtent size)
{
size_t sz = MAX(MAX(size.width, size.height), size.depth);
uint levels = 0;
uint levels = 0;
while (sz) {
sz /= 2;
levels++;
}
while (sz) {
sz /= 2;
levels++;
}
return levels;
return levels;
}
//////////////////////////////////////////////////////////////////////////
// Initalization
extern "C" void randomizeAtlas() {
uint2 *h_data = (uint2 *)atlasImage.h_data;
extern "C" void randomizeAtlas()
{
uint2 *h_data = (uint2 *)atlasImage.h_data;
// assign random texture object handles to our atlas image tiles
for (size_t i = 0; i < atlasImage.size.width * atlasImage.size.height; i++) {
// assign random texture object handles to our atlas image tiles
for (size_t i = 0; i < atlasImage.size.width * atlasImage.size.height; i++) {
#ifdef SHOW_MIPMAPS
h_data[i] = encodeTextureObject(contentImages[0].textureObject);
h_data[i] = encodeTextureObject(contentImages[0].textureObject);
#else
h_data[i] = encodeTextureObject(
contentImages[rand() % contentImages.size()].textureObject);
h_data[i] = encodeTextureObject(contentImages[rand() % contentImages.size()].textureObject);
#endif
}
}
// copy data to atlas array
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr = make_cudaPitchedPtr(
atlasImage.h_data, atlasImage.size.width * sizeof(uint2),
atlasImage.size.width, atlasImage.size.height);
copyParams.dstArray = atlasImage.dataArray;
copyParams.extent = atlasImage.size;
copyParams.extent.depth = 1;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
// copy data to atlas array
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr = make_cudaPitchedPtr(
atlasImage.h_data, atlasImage.size.width * sizeof(uint2), atlasImage.size.width, atlasImage.size.height);
copyParams.dstArray = atlasImage.dataArray;
copyParams.extent = atlasImage.size;
copyParams.extent.depth = 1;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
};
extern "C" void deinitAtlasAndImages() {
for (size_t i = 0; i < contentImages.size(); i++) {
Image &image = contentImages[i];
extern "C" void deinitAtlasAndImages()
{
for (size_t i = 0; i < contentImages.size(); i++) {
Image &image = contentImages[i];
if (image.h_data) {
free(image.h_data);
if (image.h_data) {
free(image.h_data);
}
if (image.textureObject) {
checkCudaErrors(cudaDestroyTextureObject(image.textureObject));
}
if (image.mipmapArray) {
checkCudaErrors(cudaFreeMipmappedArray(image.mipmapArray));
}
}
if (image.textureObject) {
checkCudaErrors(cudaDestroyTextureObject(image.textureObject));
if (atlasImage.h_data) {
free(atlasImage.h_data);
}
if (image.mipmapArray) {
checkCudaErrors(cudaFreeMipmappedArray(image.mipmapArray));
if (atlasImage.textureObject) {
checkCudaErrors(cudaDestroyTextureObject(atlasImage.textureObject));
}
}
if (atlasImage.h_data) {
free(atlasImage.h_data);
}
if (atlasImage.textureObject) {
checkCudaErrors(cudaDestroyTextureObject(atlasImage.textureObject));
}
if (atlasImage.dataArray) {
checkCudaErrors(cudaFreeArray(atlasImage.dataArray));
}
if (atlasImage.dataArray) {
checkCudaErrors(cudaFreeArray(atlasImage.dataArray));
}
}
extern "C" void initAtlasAndImages(const Image *images, size_t numImages,
cudaExtent atlasSize) {
// create individual textures
contentImages.resize(numImages);
extern "C" void initAtlasAndImages(const Image *images, size_t numImages, cudaExtent atlasSize)
{
// create individual textures
contentImages.resize(numImages);
for (size_t i = 0; i < numImages; i++) {
Image &image = contentImages[i];
image.size = images[i].size;
image.size.depth = 0;
image.type = cudaResourceTypeMipmappedArray;
for (size_t i = 0; i < numImages; i++) {
Image &image = contentImages[i];
image.size = images[i].size;
image.size.depth = 0;
image.type = cudaResourceTypeMipmappedArray;
// how many mipmaps we need
uint levels = getMipMapLevels(image.size);
highestLod = MAX(highestLod, (float)levels - 1);
// how many mipmaps we need
uint levels = getMipMapLevels(image.size);
highestLod = MAX(highestLod, (float)levels - 1);
cudaChannelFormatDesc desc = cudaCreateChannelDesc<uchar4>();
checkCudaErrors(cudaMallocMipmappedArray(&image.mipmapArray, &desc,
image.size, levels));
cudaChannelFormatDesc desc = cudaCreateChannelDesc<uchar4>();
checkCudaErrors(cudaMallocMipmappedArray(&image.mipmapArray, &desc, image.size, levels));
// upload level 0
cudaArray_t level0;
checkCudaErrors(cudaGetMipmappedArrayLevel(&level0, image.mipmapArray, 0));
// upload level 0
cudaArray_t level0;
checkCudaErrors(cudaGetMipmappedArrayLevel(&level0, image.mipmapArray, 0));
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr =
make_cudaPitchedPtr(images[i].h_data, image.size.width * sizeof(uchar4),
image.size.width, image.size.height);
copyParams.dstArray = level0;
copyParams.extent = image.size;
copyParams.extent.depth = 1;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr = make_cudaPitchedPtr(
images[i].h_data, image.size.width * sizeof(uchar4), image.size.width, image.size.height);
copyParams.dstArray = level0;
copyParams.extent = image.size;
copyParams.extent.depth = 1;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
// compute rest of mipmaps based on level 0
generateMipMaps(image.mipmapArray, image.size);
// compute rest of mipmaps based on level 0
generateMipMaps(image.mipmapArray, image.size);
// generate bindless texture object
// generate bindless texture object
cudaResourceDesc resDescr;
memset(&resDescr, 0, sizeof(cudaResourceDesc));
cudaResourceDesc resDescr;
memset(&resDescr, 0, sizeof(cudaResourceDesc));
resDescr.resType = cudaResourceTypeMipmappedArray;
resDescr.res.mipmap.mipmap = image.mipmapArray;
resDescr.resType = cudaResourceTypeMipmappedArray;
resDescr.res.mipmap.mipmap = image.mipmapArray;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = 1;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.mipmapFilterMode = cudaFilterModeLinear;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[2] = cudaAddressModeClamp;
texDescr.maxMipmapLevelClamp = float(levels - 1);
texDescr.readMode = cudaReadModeNormalizedFloat;
checkCudaErrors(cudaCreateTextureObject(&image.textureObject, &resDescr, &texDescr, NULL));
}
// create atlas array
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<uint2>();
checkCudaErrors(cudaMallocArray(&atlasImage.dataArray, &channelDesc, atlasSize.width, atlasSize.height));
atlasImage.h_data = malloc(atlasSize.width * atlasSize.height * sizeof(uint2));
atlasImage.type = cudaResourceTypeArray;
atlasImage.size = atlasSize;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = atlasImage.dataArray;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = 1;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.mipmapFilterMode = cudaFilterModeLinear;
texDescr.normalizedCoords = true;
texDescr.filterMode = cudaFilterModePoint;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.readMode = cudaReadModeElementType;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[2] = cudaAddressModeClamp;
checkCudaErrors(cudaCreateTextureObject(&atlasImage.textureObject, &texRes, &texDescr, NULL));
texDescr.maxMipmapLevelClamp = float(levels - 1);
texDescr.readMode = cudaReadModeNormalizedFloat;
checkCudaErrors(cudaCreateTextureObject(&image.textureObject, &resDescr,
&texDescr, NULL));
}
// create atlas array
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<uint2>();
checkCudaErrors(cudaMallocArray(&atlasImage.dataArray, &channelDesc,
atlasSize.width, atlasSize.height));
atlasImage.h_data =
malloc(atlasSize.width * atlasSize.height * sizeof(uint2));
atlasImage.type = cudaResourceTypeArray;
atlasImage.size = atlasSize;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = atlasImage.dataArray;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = true;
texDescr.filterMode = cudaFilterModePoint;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.readMode = cudaReadModeElementType;
checkCudaErrors(cudaCreateTextureObject(&atlasImage.textureObject, &texRes,
&texDescr, NULL));
randomizeAtlas();
randomizeAtlas();
}
#endif // #ifndef _SIMPLETEXTURE3D_KERNEL_CU_
#endif // #ifndef _SIMPLETEXTURE3D_KERNEL_CU_