Source code that accompanies The CUDA Handbook.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

366 lines
11 KiB

/*
*
* tex2d_opengl.cu
*
* Microdemo to illustrate the workings of 2D texturing.
*
* Build with: nvcc -I ../chLib <options> tex2d_opengl.cu, with
* platform-specific OpenGL includes and libs.
* Requires: No minimum SM requirement.
*
* Copyright (c) 2011-2012, Archaea Software, LLC.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <chError.h>
#include <GL/glut.h>
int g_width, g_height;
float g_scale = 1.0f;
char *g_texture;
cudaArray *g_arrayTexture;
uchar4 *g_hostFrameBuffer;
uchar4 *g_deviceFrameBuffer;
bool g_displayText = true;
char *
LoadTexturePPM( const char * filename )
{
int width, height, maxval;
FILE * file = NULL;
char *data = NULL;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL )
goto Error;
if ( 'P' != fgetc( file ) )
goto Error;
if ( '6' != fgetc( file ) )
goto Error;
if ( 1 != fscanf( file, "%d", &width ) )
goto Error;
if ( 1 != fscanf( file, "%d", &height ) )
goto Error;
if ( 1 != fscanf( file, "%d", &maxval ) )
goto Error;
if ( maxval != 0xff )
goto Error;
{
int ch;
do {
ch = fgetc( file );
} while ( isspace( ch ) );
}
// allocate buffer
data = (char *) malloc( width * height * 3 );
if ( ! data )
goto Error;
// read texture data
if ( 1 != fread( data, width * height * 3, 1, file ) )
goto Error;
fclose( file );
return data;
Error:
if ( file ) {
fclose( file );
}
free( data );
return NULL;
}
texture<uchar4, 2, cudaReadModeElementType> tex2d;
cudaError_t
CreateAndPopulateArray( cudaArray **ret, char *base, int width, int height )
{
uchar4 *array4 = new uchar4[width*height];
cudaChannelFormatDesc desc = cudaCreateChannelDesc<uchar4>();
cudaError_t status = cudaMallocArray( ret, &desc, width, height );
if ( cudaSuccess != status ) {
return status;
}
for ( int row = 0; row < 256; row++ ) {
char *baserow = base+(height-row-1)*3*width;
for ( int col = 0; col < 256; col++ ) {
uchar4 value;
value.z = *baserow++;
value.y = *baserow++;
value.x = *baserow++;
value.w = 0;
array4[row*width+col] = value;
}
}
return cudaMemcpy2DToArray( *ret, 0, 0, array4, width*4, width*4, height, cudaMemcpyHostToDevice );
}
__global__ void
RenderTextureUnnormalized( uchar4 *out, int width, int height )
{
for ( int j = blockIdx.x; j < height; j += gridDim.x ) {
int row = height-j-1;
for ( int col = threadIdx.x; col < width; col += blockDim.x ) {
out[row*width+col] = tex2D( tex2d, (float) col, (float) row );
}
}
}
__global__ void
RenderTextureNormalized( uchar4 *out,
int width,
int height,
int scale )
{
for ( int j = blockIdx.x; j < height; j += gridDim.x ) {
int row = height-j-1;
out = (uchar4 *) (((char *) out)+row*4*width);
float texRow = scale * (float) row / (float) height;
float invWidth = scale / (float) width;
for ( int col = threadIdx.x; col < width; col += blockDim.x ) {
float texCol = col * invWidth;
out[col] = tex2D( tex2d, texCol, texRow );
}
}
}
void glPrint(int x, int y, const char *s, void *font)
{
glColor3f(1.0, 1.0, 1.0);
glRasterPos2f(x, y);
int len = (int) strlen(s);
for (int i = 0; i < len; i++) {
glutBitmapCharacter(font, s[i]);
}
}
int g_idxAddressMode;
void displayCB(void) /* function called whenever redisplay needed */
{
glClear(GL_COLOR_BUFFER_BIT);
if ( cudaSuccess != cudaBindTextureToArray( tex2d,
g_arrayTexture,
cudaCreateChannelDesc<uchar4>() ) )
{
return;
}
if ( tex2d.normalized ) {
RenderTextureNormalized<<<g_height, 384>>>( g_deviceFrameBuffer, g_width, g_height, g_scale );
}
else {
RenderTextureUnnormalized<<<g_height, 384>>>( g_deviceFrameBuffer, g_width, g_height );
}
if ( cudaSuccess != cudaDeviceSynchronize() )
return;
glRasterPos2f( 0.0f, 0.0f );
glDrawPixels( g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, g_hostFrameBuffer );
if ( g_displayText ) {
char s[256];
int fontWidth = 9; // width of 9x15 font
int x = fontWidth; // one character of 9x15 font
int fontHeight = 15;
int y = g_height - fontHeight;
if ( tex2d.normalized ) {
glPrint( x, y, "Normalized (hit N for unnormalized)", GLUT_BITMAP_9_BY_15 );
}
else {
glPrint( x, y, "Unnormalized (hit N for normalized)", GLUT_BITMAP_9_BY_15 );
}
y -= fontHeight;
switch ( tex2d.addressMode[0] ) {
case cudaAddressModeClamp:
sprintf( s, "X address mode: Clamp %s", g_idxAddressMode ? "\0" :
"(W=wrap, M=mirror, B=border)" );
break;
case cudaAddressModeWrap:
sprintf( s, "X address mode: Wrap %s", g_idxAddressMode ? "\0" :
"(C=clamp, M=mirror, B=border)" );
break;
case cudaAddressModeMirror:
sprintf( s, "X address mode: Mirror %s", g_idxAddressMode ? "\0" :
"(C=clamp, W=wrap, B=border)" );
break;
case cudaAddressModeBorder:
sprintf( s, "X address mode: Border %s", g_idxAddressMode ? "\0" :
"(C=clamp, W=wrap, M=mirror)" );
break;
}
glPrint( x, y, s, GLUT_BITMAP_9_BY_15 );
y -= fontHeight;
switch ( tex2d.addressMode[1] ) {
case cudaAddressModeClamp:
sprintf( s, "Y address mode: Clamp %s", !g_idxAddressMode ? "\0" :
"(W=wrap, M=mirror, B=border)" );
break;
case cudaAddressModeWrap:
sprintf( s, "Y address mode: Wrap %s", !g_idxAddressMode ? "\0" :
"(C=clamp, M=mirror, B=border)" );
break;
case cudaAddressModeMirror:
sprintf( s, "Y address mode: Mirror %s", !g_idxAddressMode ? "\0" :
"(C=clamp, W=wrap, B=border)" );
break;
case cudaAddressModeBorder:
sprintf( s, "Y address mode: Border %s", !g_idxAddressMode ? "\0" :
"(C=clamp, W=wrap, M=mirror)" );
break;
}
glPrint( x, y, s, GLUT_BITMAP_9_BY_15 );
y -= fontHeight;
glPrint( x, y, "Hit X to set X addressing mode, Y to set Y addressing mode", GLUT_BITMAP_9_BY_15 );
y -= fontHeight;
glPrint( x, y, "When in normalized mode, hit 1-9 keys to set scale", GLUT_BITMAP_9_BY_15 );
y -= fontHeight;
glPrint( x, y, "T key toggles text display", GLUT_BITMAP_9_BY_15 );
}
glFlush(); /* Complete any pending operations */
}
void keyCB(unsigned char key, int x, int y) /* called on key press */
{
switch ( key ) {
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
g_scale = (float) (key-'0');
break;
case 'q':
exit(0);
break;
case 'x':
g_idxAddressMode = 0;
break;
case 'y':
g_idxAddressMode = 1;
break;
case 'n':
tex2d.normalized = ! tex2d.normalized;
break;
case 'w':
tex2d.addressMode[g_idxAddressMode] = cudaAddressModeWrap;
break;
case 'c':
tex2d.addressMode[g_idxAddressMode] = cudaAddressModeClamp;
break;
case 'm':
tex2d.addressMode[g_idxAddressMode] = cudaAddressModeMirror;
break;
case 'b':
tex2d.addressMode[g_idxAddressMode] = cudaAddressModeBorder;
break;
case 't':
g_displayText = ! g_displayText;
break;
default:
return;
}
glutPostRedisplay();
}
void
reshapeCB( int width, int height )
{
cudaError_t status;
if ( g_hostFrameBuffer ) {
cudaFreeHost( g_hostFrameBuffer );
}
g_width = width;
g_height = height;
status = cudaHostAlloc( &g_hostFrameBuffer, g_width*sizeof(uchar4)*g_height, cudaHostAllocMapped );
if ( cudaSuccess != status ) {
goto Error;
}
status = cudaHostGetDevicePointer( &g_deviceFrameBuffer, g_hostFrameBuffer, 0 );
if ( cudaSuccess != status ) {
goto Error;
}
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D(0,width,0,height);
glViewport(0,0,width,height);
glutPostRedisplay();
Error:;
}
int
main(int argc, char *argv[])
{
cudaError_t status;
int ret = 1;
g_width = 512;
g_height = 512;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(g_width,g_height);
glutCreateWindow("CUDA 2D Texturing");
g_texture = LoadTexturePPM( "TextureDemoImage.ppm" );
if ( ! g_texture ) {
fprintf( stderr, "Could not load texture\n");
goto Error;
}
cuda(SetDeviceFlags( cudaDeviceMapHost ) );
CUDART_CHECK( CreateAndPopulateArray( &g_arrayTexture, g_texture, 256, 256 ) );
glClearColor(0.0,0.0,0.0,0.0);
glutDisplayFunc(displayCB);
glutKeyboardFunc(keyCB);
glutReshapeFunc(reshapeCB);
glutMainLoop();
// we never get here
ret = 0;
Error:
return ret;
}