diff options
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gles.h')
| -rw-r--r-- | debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gles.h | 1419 |
1 files changed, 1419 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gles.h b/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gles.h new file mode 100644 index 0000000..a35984b --- /dev/null +++ b/debug_tools/WatchYourStep/ptxjitplus/inc/rendercheck_gles.h @@ -0,0 +1,1419 @@ +/** + * Copyright 1993-2015 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_GLES_H_ +#define _RENDERCHECK_GLES_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <vector> +#include <map> +#include <string> + +#include <GLES3/gl31.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_RGBA), 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, m_pboReadback); + glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*Bpp, NULL, GL_STREAM_READ); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 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, 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, 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 = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_READ_ONLY); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + // 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) + glBindFramebuffer(GL_FRAMEBUFFER, 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 = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + // release the FBO + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // release the PBO + unbindReadback(); + } + else + { + printf("CheckBackBuffer::readback() FBO->m_pImageData\n"); + // Reading direct to FBO using glReadPixels + glBindFramebuffer(GL_FRAMEBUFFER, 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)); + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + } + else + { + + printf("CheckBackBuffer::readback() PBO->m_pImageData\n"); + // read from bufObject (PBO) to system memorys image + glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject); // Bind the PBO + + // map - unmap simulates readback without the copy + void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); + + // 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); + + // read from bufObject (PBO) to system memory image + glBindBuffer(GL_PIXEL_PACK_BUFFER, 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) + { + glGenFramebuffers(1, &m_fboData.fb); + + m_fboData.colorTex = createTexture(m_eGLTarget, width, height, GL_RGBA, GL_RGBA); + m_fboData.depthTex = createTexture(m_eGLTarget, width, height, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT); + + attachTexture(m_eGLTarget, m_fboData.depthTex, GL_DEPTH_ATTACHMENT); + attachTexture(m_eGLTarget, m_fboData.colorTex, GL_COLOR_ATTACHMENT0); + + bool ret = checkStatus(__FILE__, __LINE__, false); + } + + void check_gl_error(const char *file, int line) + { + GLenum err (glGetError()); + + while(err!=GL_NO_ERROR) { + char error[64]; + + switch(err) { + case GL_INVALID_OPERATION: strcpy(error, "INVALID_OPERATION"); break; + case GL_INVALID_ENUM: strcpy(error, "INVALID_ENUM"); break; + case GL_INVALID_VALUE: strcpy(error, "INVALID_VALUE"); break; + case GL_OUT_OF_MEMORY: strcpy(error, "OUT_OF_MEMORY"); break; + case GL_INVALID_FRAMEBUFFER_OPERATION: strcpy(error, "INVALID_FRAMEBUFFER_OPERATION"); break; + } + + printf ( "GL_%s - %s : %d\n", error, file, line); + err=glGetError(); + } + } + + virtual ~CFrameBufferObject() + { + freeResources(); + } + + GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format) + { + GLuint texid; + glGenTextures(1, &texid); + + glBindTexture(target, texid); + + if (format != GL_DEPTH_COMPONENT) + { + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (internalformat == GL_DEPTH_COMPONENT24) + { + glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_INT, 0); + } + else + { + glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_BYTE, 0); + } + + check_gl_error(__FILE__, __LINE__); + glBindTexture(target, 0); + + return texid; + } + + void attachTexture(GLenum texTarget, + GLuint texId, + GLenum attachment = GL_COLOR_ATTACHMENT0, + int mipLevel = 0, + int zSlice = 0) + { + bindRenderPath(); + check_gl_error(__FILE__, __LINE__); + + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, texTarget, texId, mipLevel); + + checkStatus(__FILE__, __LINE__, false); + + 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 : 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); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + 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")); + + glGenFramebuffers(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); + + glGenerateMipmap(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 + glBindFramebuffer(GL_FRAMEBUFFER, data.fb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_eGLTarget, data.depthTex, 0); + + ret &= checkStatus(__FILE__, __LINE__, false); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 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) + { + glBindFramebuffer(GL_FRAMEBUFFER, data.resolveFB); + glGetIntegerv(GL_RED_BITS, &query); + + if (query != config.redbits) + { + ret = false; + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + ret &= checkStatus(__FILE__, __LINE__, true); + + return ret; + } + + virtual void freeResources() + { + if (m_fboData.fb) + { + glDeleteFramebuffers(1, &m_fboData.fb); + } + + if (m_fboData.resolveFB) + { + glDeleteFramebuffers(1, &m_fboData.resolveFB); + } + + if (m_fboData.colorRB) + { + glDeleteRenderbuffers(1, &m_fboData.colorRB); + } + + if (m_fboData.depthRB) + { + glDeleteRenderbuffers(1, &m_fboData.depthRB); + } + + if (m_fboData.colorTex) + { + glDeleteTextures(1, &m_fboData.colorTex); + } + + if (m_fboData.depthTex) + { + glDeleteTextures(1, &m_fboData.depthTex); + } + + glDeleteProgram(m_textureProgram); + glDeleteProgram(m_overlayProgram); + } + + virtual bool checkStatus(const char *zfile, int line, bool silent) + { + GLenum status; + status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + printf("<%s : %d> - this one ", zfile, line); + } + + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE: + break; + + case GL_FRAMEBUFFER_UNSUPPORTED: + if (!silent) + { + printf("Unsupported framebuffer format\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + if (!silent) + { + printf("Framebuffer incomplete, missing attachment\n"); + } + + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + if (!silent) + { + printf("Framebuffer incomplete, duplicate attachment\n"); + } + + return false; + + default: + assert(0); + return false; + } + + return true; + } + + // bind to the FrameBuffer Object + void bindRenderPath() + { + glBindFramebuffer(GL_FRAMEBUFFER, m_fboData.fb); + } + + // release current FrameBuffer Object + void unbindRenderPath() + { + glBindFramebuffer(GL_FRAMEBUFFER, 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) + { + } + + void check_gl_error(const char *file, int line) + { + GLenum err (glGetError()); + + while(err!=GL_NO_ERROR) + { + char error[64]; + + switch(err) + { + case GL_INVALID_OPERATION: strcpy(error, "INVALID_OPERATION"); break; + case GL_INVALID_ENUM: strcpy(error, "INVALID_ENUM"); break; + case GL_INVALID_VALUE: strcpy(error, "INVALID_VALUE"); break; + case GL_OUT_OF_MEMORY: strcpy(error, "OUT_OF_MEMORY"); break; + case GL_INVALID_FRAMEBUFFER_OPERATION: strcpy(error, "INVALID_FRAMEBUFFER_OPERATION"); break; + } + + printf ( "GL_%s - %s : %d\n", error, file, line); + err=glGetError(); + } + } + + virtual ~CheckFBO() + { + } + + virtual bool checkStatus(const char *zfile, int line, bool silent) + { + GLenum status; + status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + printf("<%s : %d> - here ", zfile, line); + } + + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE: + break; + + case GL_FRAMEBUFFER_UNSUPPORTED: + if (!silent) + { + printf("Unsupported framebuffer format\n"); + } + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + if (!silent) + { + printf("Framebuffer incomplete, missing attachment\n"); + } + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + if (!silent) + { + printf("Framebuffer incomplete, duplicate attachment\n"); + } + return false; + + case GL_FRAMEBUFFER_UNDEFINED: + if (!silent) + { + printf("Framebuffer undefined\n"); + } + return false; + + default: + if (!silent) + { + printf("Framebuffer incomplete, default state\n"); + } + 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) + glBindFramebuffer(GL_FRAMEBUFFER, m_pFrameBufferObject->getFbo()); + + ret = checkStatus(__FILE__, __LINE__, false); + + if (!ret) + { + printf("CheckFBO::readback() glBindFramebuffer checkStatus = %d\n", ret); + } + + // Now initiate the readback to PBO + glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + + ret = checkStatus(__FILE__, __LINE__, false); + + check_gl_error(__FILE__, __LINE__); + + if (!ret) + { + printf("CheckFBO::readback() FBO->PBO checkStatus = %d\n", ret); + } + + int nBufferSize = 0; + glGetBufferParameteriv(GL_PIXEL_PACK_BUFFER, GL_BUFFER_SIZE, &nBufferSize); + + if (nBufferSize != width*height*m_Bpp) + { + printf("Buffer size incorrect, exiting..\n"); + exit(EXIT_FAILURE); + } + + // map - unmap simulates readback without the copy + void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); + check_gl_error(__FILE__, __LINE__); + + if (ioMem != NULL) + { + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + } + else + { + printf("\nError: Unable to map the PBO\n"); + exit(EXIT_FAILURE); + } + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + // release the FBO + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // release the PBO + unbindReadback(); + } + else + { + // Reading back from FBO using glReadPixels + glBindFramebuffer(GL_FRAMEBUFFER, 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)); + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, 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) + glBindFramebuffer(GL_FRAMEBUFFER, 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 = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + // release the FBO + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // release the PBO + unbindReadback(); + } + else + { + printf("CheckFBO::readback() FBO->m_pImageData\n"); + // Reading direct to FBO using glReadPixels + glBindFramebuffer(GL_FRAMEBUFFER, 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)); + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + } + else + { + printf("CheckFBO::readback() PBO->m_pImageData\n"); + // read from bufObject (PBO) to system memorys image + glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject); // Bind the PBO + + // map - unmap simulates readback without the copy + void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT); + memcpy(m_pImageData, ioMem, width*height*m_Bpp); + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + // read from bufObject (PBO) to system memory image + glBindBuffer(GL_PIXEL_PACK_BUFFER, 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_GLES_H_ + |
