diff options
| author | Deval Shah <[email protected]> | 2018-11-09 21:14:55 -0800 |
|---|---|---|
| committer | Deval Shah <[email protected]> | 2018-11-09 21:14:55 -0800 |
| commit | 36496d4ab2ff1088979e0f3137c54592652c37da (patch) | |
| tree | ca449a4dc68abd5355764ae1bc50ca6ea5888fec /debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h | |
| parent | 0265d747b06c18d0a1ee00fb1641032201425c97 (diff) | |
| parent | 0e8d4f190940681601bdf7f95a5686baa0b6463b (diff) | |
resolving merge conflict
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h')
| -rw-r--r-- | debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h | 1473 |
1 files changed, 1473 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h b/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h new file mode 100644 index 0000000..3c5c036 --- /dev/null +++ b/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gl.h @@ -0,0 +1,1473 @@ +/** + * Copyright 1993-2013 NVIDIA Corporation. All rights reserved. + * + * Please refer to the NVIDIA end user license agreement (EULA) associated + * with this source code for terms and conditions that govern your use of + * this software. Any use, reproduction, disclosure, or distribution of + * this software and related documentation outside the terms of the EULA + * is strictly prohibited. + * + */ + + +#ifndef _RENDERCHECK_GL_H_ +#define _RENDERCHECK_GL_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <vector> +#include <map> +#include <string> + +#if defined(__APPLE__) || defined(MACOSX) +#include <GLUT/glut.h> +#else +#include <GL/freeglut.h> +#endif + +#include <nvShaderUtils.h> + +#include <helper_image.h> + + +using std::vector; +using std::map; +using std::string; + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +#if _DEBUG +#define CHECK_FBO checkStatus(__FILE__, __LINE__, true) +#else +#define CHECK_FBO true +#endif + + + +class CheckRender +{ + public: + CheckRender(unsigned int width, unsigned int height, unsigned int Bpp, + bool bQAReadback, bool bUseFBO, bool bUsePBO) : + m_Width(width), m_Height(height), m_Bpp(Bpp), m_bQAReadback(bQAReadback), + m_bUseFBO(bUseFBO), m_bUsePBO(bUsePBO), m_PixelFormat(GL_BGRA), m_fThresholdCompare(0.0f) + { + allocateMemory(width, height, Bpp, bUseFBO, bUsePBO); + } + + virtual ~CheckRender() + { + // Release PBO resources + if (m_bUsePBO) + { + glDeleteBuffers(1, &m_pboReadback); + m_pboReadback = 0; + } + + free(m_pImageData); + } + + virtual void allocateMemory(unsigned int width, unsigned int height, unsigned int Bpp, + bool bUseFBO, bool bUsePBO) + { + // Create the PBO for readbacks + if (bUsePBO) + { + glGenBuffers(1, &m_pboReadback); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, m_pboReadback); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width*height*Bpp, NULL, GL_STREAM_READ); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + } + + m_pImageData = (unsigned char *)malloc(width*height*Bpp); // This is the image data stored in system memory + } + + + virtual void setExecPath(char *path) + { + m_ExecPath = path; + } + virtual void EnableQAReadback(bool bStatus) + { + m_bQAReadback = bStatus; + } + virtual bool IsQAReadback() + { + return m_bQAReadback; + } + virtual bool IsFBO() + { + return m_bUseFBO; + } + virtual bool IsPBO() + { + return m_bUsePBO; + } + virtual void *imageData() + { + return m_pImageData; + } + + // Interface to this class functions + virtual void setPixelFormat(GLenum format) + { + m_PixelFormat = format; + } + virtual int getPixelFormat() + { + return m_PixelFormat; + } + virtual bool checkStatus(const char *zfile, int line, bool silent) = 0; + virtual bool readback(GLuint width, GLuint height) = 0; + virtual bool readback(GLuint width, GLuint height, GLuint bufObject) = 0; + virtual bool readback(GLuint width, GLuint height, unsigned char *membuf) = 0; + + virtual void bindReadback() + { + if (!m_bQAReadback) + { + printf("CheckRender::bindReadback() uninitialized!\n"); + return; + } + + if (m_bUsePBO) + { + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, m_pboReadback); // Bind the PBO + } + } + + virtual void unbindReadback() + { + if (!m_bQAReadback) + { + printf("CheckRender::unbindReadback() uninitialized!\n"); + return; + } + + if (m_bUsePBO) + { + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // Release the bind on the PBO + } + } + + virtual void savePGM(const char *zfilename, bool bInvert, void **ppReadBuf) + { + if (zfilename != NULL) + { + if (bInvert) + { + unsigned char *readBuf; + unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height); + + for (unsigned int y=0; y < m_Height; y++) + { + if (ppReadBuf) + { + readBuf = *(unsigned char **)ppReadBuf; + } + else + { + readBuf = (unsigned char *)m_pImageData; + } + + memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*(m_Height-1-y)), m_Width); + } + + // we copy the results back to original system buffer + if (ppReadBuf) + { + memcpy(*ppReadBuf, writeBuf, m_Width*m_Height); + } + else + { + memcpy(m_pImageData, writeBuf, m_Width*m_Height); + } + + free(writeBuf); + } + + printf("> Saving PGM: <%s>\n", zfilename); + + if (ppReadBuf) + { + sdkSavePGM<unsigned char>(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); + } + else + { + sdkSavePGM<unsigned char>(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); + } + } + } + + virtual void savePPM(const char *zfilename, bool bInvert, void **ppReadBuf) + { + if (zfilename != NULL) + { + if (bInvert) + { + unsigned char *readBuf; + unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height * m_Bpp); + + for (unsigned int y=0; y < m_Height; y++) + { + if (ppReadBuf) + { + readBuf = *(unsigned char **)ppReadBuf; + } + else + { + readBuf = (unsigned char *)m_pImageData; + } + + memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*m_Bpp*(m_Height-1-y)), m_Width*m_Bpp); + } + + // we copy the results back to original system buffer + if (ppReadBuf) + { + memcpy(*ppReadBuf, writeBuf, m_Width*m_Height*m_Bpp); + } + else + { + memcpy(m_pImageData, writeBuf, m_Width*m_Height*m_Bpp); + } + + free(writeBuf); + } + + printf("> Saving PPM: <%s>\n", zfilename); + + if (ppReadBuf) + { + sdkSavePPM4ub(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height); + } + else + { + sdkSavePPM4ub(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height); + } + } + } + + virtual bool PGMvsPGM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) + { + unsigned char *src_data = NULL, *ref_data = NULL; + unsigned long error_count = 0; + unsigned int width, height; + + char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); + + if (ref_file_path == NULL) + { + printf("CheckRender::PGMvsPGM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); + printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); + printf("Aborting comparison!\n"); + printf(" FAILED\n"); + error_count++; + } + else + { + + if (src_file == NULL || ref_file_path == NULL) + { + printf("PGMvsPGM: Aborting comparison\n"); + return false; + } + + printf(" src_file <%s>\n", src_file); + printf(" ref_file <%s>\n", ref_file_path); + + if (sdkLoadPPMub(ref_file_path, &ref_data, &width, &height) != true) + { + printf("PGMvsPGM: unable to load ref image file: %s\n", ref_file_path); + return false; + } + + if (sdkLoadPPMub(src_file, &src_data, &width, &height) != true) + { + printf("PGMvsPGM: unable to load src image file: %s\n", src_file); + return false; + } + + printf("PGMvsPGM: comparing images size (%d,%d) epsilon(%2.4f), threshold(%4.2f%%)\n", m_Height, m_Width, epsilon, threshold*100); + + if (compareDataAsFloatThreshold<unsigned char, float>(ref_data, src_data, m_Height*m_Width, epsilon, threshold) == false) + { + error_count = 1; + } + } + + if (error_count == 0) + { + printf(" OK\n"); + } + else + { + printf(" FAILURE: %d errors...\n", (unsigned int)error_count); + } + + return (error_count == 0); // returns true if all pixels pass + } + + virtual bool PPMvsPPM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f) + { + unsigned long error_count = 0; + + char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); + + if (ref_file_path == NULL) + { + printf("CheckRender::PPMvsPPM unable to find <%s> in <%s> Aborting comparison!\n", ref_file, m_ExecPath.c_str()); + printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); + printf("Aborting comparison!\n"); + printf(" FAILED\n"); + error_count++; + } + + if (src_file == NULL || ref_file_path == NULL) + { + printf("PPMvsPPM: Aborting comparison\n"); + return false; + } + + printf(" src_file <%s>\n", src_file); + printf(" ref_file <%s>\n", ref_file_path); + return (sdkComparePPM(src_file, ref_file_path, epsilon, threshold, true) == true ? true : false); + } + + + void setThresholdCompare(float value) + { + m_fThresholdCompare = value; + } + + virtual void dumpBin(void *data, unsigned int bytes, const char *filename) + { + FILE *fp; + printf("CheckRender::dumpBin: <%s>\n", filename); + FOPEN(fp, filename, "wb"); + fwrite(data, bytes, 1, fp); + fflush(fp); + fclose(fp); + } + + virtual bool compareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) + { + unsigned int *src_buffer, *ref_buffer; + FILE *src_fp = NULL, *ref_fp = NULL; + + unsigned long error_count = 0; + size_t fsize = 0; + + FOPEN(src_fp, src_file, "rb"); + + if (src_fp == NULL) + { + printf("compareBin2Bin <unsigned int> unable to open src_file: %s\n", src_file); + error_count++; + } + + char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); + + if (ref_file_path == NULL) + { + printf("compareBin2Bin <unsigned int> unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); + printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", ref_file); + printf("Aborting comparison!\n"); + printf(" FAILED\n"); + error_count++; + + if (src_fp) + { + fclose(src_fp); + } + + if (ref_fp) + { + fclose(ref_fp); + } + } + else + { + FOPEN(ref_fp, ref_file_path, "rb"); + + if (ref_fp == NULL) + { + printf("compareBin2Bin <unsigned int> unable to open ref_file: %s\n", ref_file_path); + error_count++; + } + + if (src_fp && ref_fp) + { + src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); + ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int)); + + fsize = fread(src_buffer, sizeof(unsigned int), nelements, src_fp); + + if (fsize != nelements) + { + printf("compareBin2Bin <unsigned int> failed to read %u elements from %s\n", nelements, src_file); + error_count++; + } + + fsize = fread(ref_buffer, sizeof(unsigned int), nelements, ref_fp); + + if (fsize == 0) + { + printf("compareBin2Bin <unsigned int> failed to read %u elements from %s\n", nelements, ref_file_path); + error_count++; + } + + + printf("> compareBin2Bin <unsigned int> nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); + printf(" src_file <%s>\n", src_file); + printf(" ref_file <%s>\n", ref_file_path); + + if (!compareData<unsigned int, float>(ref_buffer, src_buffer, nelements, epsilon, threshold)) + { + error_count++; + } + + fclose(src_fp); + fclose(ref_fp); + + free(src_buffer); + free(ref_buffer); + } + else + { + if (src_fp) + { + fclose(src_fp); + } + + if (ref_fp) + { + fclose(ref_fp); + } + } + } + + if (error_count == 0) + { + printf(" OK\n"); + } + else + { + printf(" FAILURE: %d errors...\n", (unsigned int)error_count); + } + + return (error_count == 0); // returns true if all pixels pass + } + + virtual bool compareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold) + { + float *src_buffer, *ref_buffer; + FILE *src_fp = NULL, *ref_fp = NULL; + size_t fsize = 0; + + unsigned long error_count = 0; + + FOPEN(src_fp, src_file, "rb"); + + if (src_fp == NULL) + { + printf("compareBin2Bin <float> unable to open src_file: %s\n", src_file); + error_count = 1; + } + + char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str()); + + if (ref_file_path == NULL) + { + printf("compareBin2Bin <float> unable to find <%s> in <%s>\n", ref_file, m_ExecPath.c_str()); + printf(">>> Check info.xml and [project//data] folder <%s> <<<\n", m_ExecPath.c_str()); + printf("Aborting comparison!\n"); + printf(" FAILED\n"); + error_count++; + + if (src_fp) + { + fclose(src_fp); + } + + if (ref_fp) + { + fclose(ref_fp); + } + } + else + { + FOPEN(ref_fp, ref_file_path, "rb"); + + if (ref_fp == NULL) + { + printf("compareBin2Bin <float> unable to open ref_file: %s\n", ref_file_path); + error_count = 1; + } + + if (src_fp && ref_fp) + { + src_buffer = (float *)malloc(nelements*sizeof(float)); + ref_buffer = (float *)malloc(nelements*sizeof(float)); + + fsize = fread(src_buffer, sizeof(float), nelements, src_fp); + + if (fsize != nelements) + { + printf("compareBin2Bin <float> failed to read %u elements from %s\n", nelements, src_file); + error_count++; + } + + fsize = fread(ref_buffer, sizeof(float), nelements, ref_fp); + + if (fsize == 0) + { + printf("compareBin2Bin <float> failed to read %u elements from %s\n", nelements, ref_file_path); + error_count++; + } + + printf("> compareBin2Bin <float> nelements=%d, epsilon=%4.2f, threshold=%4.2f\n", nelements, epsilon, threshold); + printf(" src_file <%s>\n", src_file); + printf(" ref_file <%s>\n", ref_file_path); + + if (!compareDataAsFloatThreshold<float, float>(ref_buffer, src_buffer, nelements, epsilon, threshold)) + { + error_count++; + } + + fclose(src_fp); + fclose(ref_fp); + + free(src_buffer); + free(ref_buffer); + } + else + { + if (src_fp) + { + fclose(src_fp); + } + + if (ref_fp) + { + fclose(ref_fp); + } + } + } + + if (error_count == 0) + { + printf(" OK\n"); + } + else + { + printf(" FAILURE: %d errors...\n", (unsigned int)error_count); + } + + return (error_count == 0); // returns true if all pixels pass + } + + + protected: + unsigned int m_Width, m_Height, m_Bpp; + unsigned char *m_pImageData; // This is the image data stored in system memory + bool m_bQAReadback, m_bUseFBO, m_bUsePBO; + GLuint m_pboReadback; + GLenum m_PixelFormat; + float m_fThresholdCompare; + string m_ExecPath; +}; + + +class CheckBackBuffer : public CheckRender +{ + public: + CheckBackBuffer(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseOpenGL = true) : + CheckRender(width, height, Bpp, false, false, bUseOpenGL) + { + } + + virtual ~CheckBackBuffer() + { + } + + virtual bool checkStatus(const char *zfile, int line, bool silent) + { + GLenum nErrorCode = glGetError(); + + if (nErrorCode != GL_NO_ERROR) + { + if (!silent) + { + printf("Assertion failed(%s,%d): %s\n", zfile, line, gluErrorString(nErrorCode)); + } + } + + return true; + } + + virtual bool readback(GLuint width, GLuint height) + { + bool ret = false; + + if (m_bUsePBO) + { + // binds the PBO for readback + bindReadback(); + + // Initiate the readback BLT from BackBuffer->PBO->membuf + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckBackBuffer::glReadPixels() checkStatus = %d\n", ret); + } + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // release the PBO + unbindReadback(); + } + else + { + // reading direct from the backbuffer + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); + } + + return ret; + } + + virtual bool readback(GLuint width, GLuint height, GLuint bufObject) + { + bool ret = false; + + if (m_bUseFBO) + { + if (m_bUsePBO) + { + printf("CheckBackBuffer::readback() FBO->PBO->m_pImageData\n"); + // binds the PBO for readback + bindReadback(); + + // bind FBO buffer (we want to transfer FBO -> PBO) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); + + // Now initiate the readback to PBO + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckBackBuffer::readback() FBO->PBO checkStatus = %d\n", ret); + } + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // release the FBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + // release the PBO + unbindReadback(); + } + else + { + printf("CheckBackBuffer::readback() FBO->m_pImageData\n"); + // Reading direct to FBO using glReadPixels + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckBackBuffer::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", bufObject, ret); + } + + glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT)); + ret &= checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckBackBuffer::readback::glReadBuffer() fbo=%d checkStatus = %d\n", bufObject, ret); + } + + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + } + else + { + + printf("CheckBackBuffer::readback() PBO->m_pImageData\n"); + // read from bufObject (PBO) to system memorys image + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject); // Bind the PBO + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + + // allocate a buffer so we can flip the image + unsigned char *temp_buf = (unsigned char *)malloc(width*height*m_Bpp); + memcpy(temp_buf, ioMem, width*height*m_Bpp); + + // let's flip the image as we copy + for (unsigned int y = 0; y < height; y++) + { + memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(temp_buf[y*width*m_Bpp]), width*m_Bpp); + } + + free(temp_buf); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // read from bufObject (PBO) to system memory image + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // unBind the PBO + } + + return CHECK_FBO; + } + + virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) + { + // let's flip the image as we copy + for (unsigned int y = 0; y < height; y++) + { + memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); + } + + return true; + } + + private: + virtual void bindFragmentProgram() {}; + virtual void bindRenderPath() {}; + virtual void unbindRenderPath() {}; + + // bind to the BackBuffer to Texture + virtual void bindTexture() {}; + + // release this bind + virtual void unbindTexture() {}; +}; + + +// structure defining the properties of a single buffer +struct bufferConfig +{ + string name; + GLenum format; + int bits; +}; + +// structures defining properties of an FBO +struct fboConfig +{ + string name; + GLenum colorFormat; + GLenum depthFormat; + int redbits; + int depthBits; + int depthSamples; + int coverageSamples; +}; + +struct fboData +{ + GLuint colorTex; //color texture + GLuint depthTex; //depth texture + GLuint fb; // render framebuffer + GLuint resolveFB; //multisample resolve target + GLuint colorRB; //color render buffer + GLuint depthRB; // depth render buffer +}; + + +class CFrameBufferObject +{ + public: + CFrameBufferObject(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFloat, GLenum eTarget) : + m_Width(width), + m_Height(height), + m_bUseFloat(bUseFloat), + m_eGLTarget(eTarget) + { + glGenFramebuffersEXT(1, &m_fboData.fb); + + m_fboData.colorTex = createTexture(m_eGLTarget, width, height, + (bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8), GL_RGBA); + + m_fboData.depthTex = createTexture(m_eGLTarget, width, height, + GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT); + + attachTexture(m_eGLTarget, m_fboData.colorTex, GL_COLOR_ATTACHMENT0_EXT); + attachTexture(m_eGLTarget, m_fboData.depthTex, GL_DEPTH_ATTACHMENT_EXT); + + // bool ret = checkStatus(__FILE__, __LINE__, true); + } + + virtual ~CFrameBufferObject() + { + // freeResources(); + } + + GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format) + { + GLuint texid; + glGenTextures(1, &texid); + glBindTexture(target, texid); + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0); + return texid; + } + + void attachTexture(GLenum texTarget, + GLuint texId, + GLenum attachment = GL_COLOR_ATTACHMENT0_EXT, + int mipLevel = 0, + int zSlice = 0) + { + bindRenderPath(); + + switch (texTarget) + { + case GL_TEXTURE_1D: + glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, + GL_TEXTURE_1D, texId, mipLevel); + break; + + case GL_TEXTURE_3D: + glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, + GL_TEXTURE_3D, texId, mipLevel, zSlice); + break; + + default: + // Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + texTarget, texId, mipLevel); + break; + } + + unbindRenderPath(); + } + + bool initialize(unsigned width, unsigned height, fboConfig &rConfigFBO, fboData &rActiveFBO) + { + //Framebuffer config options + vector<bufferConfig> colorConfigs; + vector<bufferConfig> depthConfigs; + bufferConfig temp; + + //add default color configs + temp.name = (m_bUseFloat ? "RGBA32F" : "RGBA8"); + temp.bits = (m_bUseFloat ? 32 : 8); + temp.format = (m_bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8); + colorConfigs.push_back(temp); + + //add default depth configs + temp.name = "D24"; + temp.bits = 24; + temp.format = GL_DEPTH_COMPONENT24; + depthConfigs.push_back(temp); + + // If the FBO can be created, add it to the list of available configs, and make a menu entry + string root = colorConfigs[0].name + " " + depthConfigs[0].name; + + rConfigFBO.colorFormat = colorConfigs[0].format; + rConfigFBO.depthFormat = depthConfigs[0].format; + rConfigFBO.redbits = colorConfigs[0].bits; + rConfigFBO.depthBits = depthConfigs[0].bits; + + //single sample + rConfigFBO.name = root; + rConfigFBO.coverageSamples = 0; + rConfigFBO.depthSamples = 0; + + create(width, height, rConfigFBO, rActiveFBO); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + if (m_bUseFloat) + { + // load fragment programs + const char *strTextureProgram2D = + "!!ARBfp1.0\n" + "TEX result.color, fragment.texcoord[0], texture[0], 2D;\n" + "END\n"; + + m_textureProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strTextureProgram2D); + + const char *strOverlayProgram = + "!!ARBfp1.0\n" + "TEMP t;\n" + "TEX t, fragment.texcoord[0], texture[0], 2D;\n" + "MOV result.color, t;\n" + "END\n"; + + m_overlayProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strOverlayProgram); + } + + return CHECK_FBO; + } + + bool create(GLuint width, GLuint height, fboConfig &config, fboData &data) + { + bool multisample = config.depthSamples > 0; + bool ret = true; + GLint query; + + printf("\nCreating FBO <%s> (%dx%d) Float:%s\n", config.name.c_str(), (int)width, (int)height, (m_bUseFloat ? "Y":"N")); + + glGenFramebuffersEXT(1, &data.fb); + glGenTextures(1, &data.colorTex); + + // init texture + glBindTexture(m_eGLTarget, data.colorTex); + glTexImage2D(m_eGLTarget, 0, config.colorFormat, + width, height, 0, GL_RGBA, + (m_bUseFloat ? GL_FLOAT : GL_UNSIGNED_BYTE), + NULL); + + glGenerateMipmapEXT(m_eGLTarget); + + glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); + + { + glGenTextures(1, &data.depthTex); + data.depthRB = 0; + data.colorRB = 0; + data.resolveFB = 0; + + //non-multisample, so bind things directly to the FBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_eGLTarget, data.colorTex, 0); + + glBindTexture(m_eGLTarget, data.depthTex); + glTexImage2D(m_eGLTarget, 0, config.depthFormat, + width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + + glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR); + glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR); + glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(m_eGLTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_eGLTarget, data.depthTex, 0); + + ret &= checkStatus(__FILE__, __LINE__, true); + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb); + glGetIntegerv(GL_RED_BITS, &query); + + if (query != config.redbits) + { + ret = false; + } + + glGetIntegerv(GL_DEPTH_BITS, &query); + + if (query != config.depthBits) + { + ret = false; + } + + if (multisample) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.resolveFB); + glGetIntegerv(GL_RED_BITS, &query); + + if (query != config.redbits) + { + ret = false; + } + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + ret &= checkStatus(__FILE__, __LINE__, true); + + return ret; + } + + virtual void freeResources() + { + if (m_fboData.fb) + { + glDeleteFramebuffersEXT(1, &m_fboData.fb); + } + + if (m_fboData.resolveFB) + { + glDeleteFramebuffersEXT(1, &m_fboData.resolveFB); + } + + if (m_fboData.colorRB) + { + glDeleteRenderbuffersEXT(1, &m_fboData.colorRB); + } + + if (m_fboData.depthRB) + { + glDeleteRenderbuffersEXT(1, &m_fboData.depthRB); + } + + if (m_fboData.colorTex) + { + glDeleteTextures(1, &m_fboData.colorTex); + } + + if (m_fboData.depthTex) + { + glDeleteTextures(1, &m_fboData.depthTex); + } + + glDeleteProgramsARB(1, &m_textureProgram); + glDeleteProgramsARB(1, &m_overlayProgram); + } + + virtual bool checkStatus(const char *zfile, int line, bool silent) + { + GLenum status; + status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + printf("<%s : %d> - ", zfile, line); + } + + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + if (!silent) + { + printf("Unsupported framebuffer format\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing attachment\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + if (!silent) + { + printf("Framebuffer incomplete, duplicate attachment\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + if (!silent) + { + printf("Framebuffer incomplete, attached images must have same dimensions\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + if (!silent) + { + printf("Framebuffer incomplete, attached images must have same format\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing draw buffer\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing read buffer\n"); + } + + return false; + + default: + assert(0); + return false; + } + + return true; + } + + virtual void renderQuad(int width, int height, GLenum eTarget) + { + float width_norm = (float)width/(float)m_Width, + height_norm = (float)height/(float)m_Height; + + // Bind the FBO texture for the display path + glBindTexture(eTarget, m_fboData.colorTex); + + glGenerateMipmapEXT(GL_TEXTURE_2D); + glBindTexture(eTarget, 0); + + // now render to the full screen using this texture + glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram); + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glDisable(GL_DEPTH_TEST); + + glBegin(GL_QUADS); + { + glVertex2f(0.0f , 0.0f); + glTexCoord2f(0.0f , 0.0f); + glVertex2f(0.0f , height_norm); + glTexCoord2f(width_norm, 0.0f); + glVertex2f(width_norm, height_norm); + glTexCoord2f(width_norm, height_norm); + glVertex2f(width_norm, 0.0f); + glTexCoord2f(0.0f , height_norm); + } + glEnd(); + + // Release the FBO texture (finished rendering) + glBindTexture(eTarget, 0); + } + + // bind to the Fragment Program + void bindFragmentProgram() + { + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram); + glEnable(GL_FRAGMENT_PROGRAM_ARB); + } + + // bind to the FrameBuffer Object + void bindRenderPath() + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboData.fb); + } + + // release current FrameBuffer Object + void unbindRenderPath() + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + + // bind to the FBO to Texture + void bindTexture() + { + glBindTexture(m_eGLTarget, m_fboData.colorTex); + } + + // release this bind + void unbindTexture() + { + glBindTexture(m_eGLTarget, 0); + } + + GLuint getFbo() + { + return m_fboData.fb; + } + GLuint getTex() + { + return m_fboData.colorTex; + } + GLuint getDepthTex() + { + return m_fboData.depthTex; + } + + private: + GLuint m_Width, m_Height; + fboData m_fboData; + fboConfig m_fboConfig; + + GLuint m_textureProgram; + GLuint m_overlayProgram; + + bool m_bUseFloat; + GLenum m_eGLTarget; +}; + + +// CheckFBO - render and verify contents of the FBO +class CheckFBO: public CheckRender +{ + public: + CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp) : + CheckRender(width, height, Bpp, false, false, true), + m_pFrameBufferObject(NULL) + { + } + + CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp, CFrameBufferObject *pFrameBufferObject) : + CheckRender(width, height, Bpp, false, true, true), + m_pFrameBufferObject(pFrameBufferObject) + { + } + + virtual ~CheckFBO() + { + } + + virtual bool checkStatus(const char *zfile, int line, bool silent) + { + GLenum status; + status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + printf("<%s : %d> - ", zfile, line); + } + + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + if (!silent) + { + printf("Unsupported framebuffer format\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing attachment\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + if (!silent) + { + printf("Framebuffer incomplete, duplicate attachment\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + if (!silent) + { + printf("Framebuffer incomplete, attached images must have same dimensions\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + if (!silent) + { + printf("Framebuffer incomplete, attached images must have same format\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing draw buffer\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + if (!silent) + { + printf("Framebuffer incomplete, missing read buffer\n"); + } + + return false; + + default: + assert(0); + return false; + } + + return true; + } + + virtual bool readback(GLuint width, GLuint height) + { + bool ret = false; + + if (m_bUsePBO) + { + // binds the PBO for readback + bindReadback(); + + // bind FBO buffer (we want to transfer FBO -> PBO) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo()); + + // Now initiate the readback to PBO + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); + } + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // release the FBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + // release the PBO + unbindReadback(); + } + else + { + // Reading back from FBO using glReadPixels + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo()); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback::glBindFramebufferEXT() checkStatus = %d\n", ret); + } + + glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT)); + ret &= checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback::glReadBuffer() checkStatus = %d\n", ret); + } + + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + + return CHECK_FBO; + } + + virtual bool readback(GLuint width, GLuint height, GLuint bufObject) + { + bool ret = false; + + if (m_bUseFBO) + { + if (m_bUsePBO) + { + printf("CheckFBO::readback() FBO->PBO->m_pImageData\n"); + // binds the PBO for readback + bindReadback(); + + // bind FBO buffer (we want to transfer FBO -> PBO) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); + + // Now initiate the readback to PBO + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); + } + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // release the FBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + // release the PBO + unbindReadback(); + } + else + { + printf("CheckFBO::readback() FBO->m_pImageData\n"); + // Reading direct to FBO using glReadPixels + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject); + ret = checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); + } + + glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT)); + ret &= checkStatus(__FILE__, __LINE__, true); + + if (!ret) + { + printf("CheckFBO::readback::glReadBuffer() fbo=%d checkStatus = %d\n", (int)bufObject, (int)ret); + } + + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + } + else + { + printf("CheckFBO::readback() PBO->m_pImageData\n"); + // read from bufObject (PBO) to system memorys image + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject); // Bind the PBO + + // map - unmap simulates readback without the copy + void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); + + // read from bufObject (PBO) to system memory image + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); // unBind the PBO + } + + return CHECK_FBO; + } + + virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf) + { + // let's flip the image as we copy + for (unsigned int y = 0; y < height; y++) + { + memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp); + } + + return true; + } + + private: + CFrameBufferObject *m_pFrameBufferObject; +}; + +#endif // _RENDERCHECK_GL_H_ + |
