/* * Test reading back an RGBA texture as luminance. */ static bool test_rgba(void) { static const GLfloat rgbaImage[4] = { 0.5, 0.25, 0.125, 1.0 }; static const GLfloat lumImage[1] = { 0.5 }; GLuint tex; GLfloat test[2*2*4]; /* create 1x1 GL_RGBA texture */ glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_FLOAT, rgbaImage); /* Get and check luminance image */ glGetTextureImage(tex, 0, GL_LUMINANCE, GL_FLOAT, sizeof(test), test); if (!lum_equal(lumImage, test)) { printf("%s: glGetTextureImage(GL_RGBA as" " GL_LUMINANCE) failed\n", TestName); printf(" Expected %g Found %g\n", lumImage[0], test[0]); return false; } return true; }
bool GSTextureOGL::Map(GSMap& m, const GSVector4i* r) { // LOTS OF CRAP CODE!!!! PLEASE FIX ME !!! if (m_type != GSTexture::Offscreen) return false; // The fastest way will be to use a PBO to read the data asynchronously. Unfortunately GSdx // architecture is waiting the data right now. #if 0 // Maybe it is as good as the code below. I don't know glGetTextureImage(m_texture_id, GL_TEX_LEVEL_0, m_int_format, m_int_type, 1024*1024*16, m_local_buffer); #else // Bind the texture to the read framebuffer to avoid any disturbance glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0); glPixelStorei(GL_PACK_ALIGNMENT, m_int_alignment); glReadPixels(0, 0, m_size.x, m_size.y, m_int_format, m_int_type, m_local_buffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); #endif m.bits = m_local_buffer; m.pitch = m_size.x << m_int_shift; return true; }
bool kit::Texture::saveToFile(const std::string&filename) { // Fetch data from GPU unsigned char * data = new unsigned char[(m_resolution.x * m_resolution.y) * 4]; #ifndef KIT_SHITTY_INTEL glGetTextureImage(m_glHandle, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLsizei)(((m_resolution.x * m_resolution.y) * 4) * sizeof(unsigned char)), &data[0]); #else bind(); glGetTexImage(m_type, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); #endif stbi_write_set_flip_vertically_on_save(1); // Write data to disk if(stbi_write_tga(filename.c_str(), m_resolution.x, m_resolution.y, 4, (void*)data) == 0) { KIT_ERR("Failed to write image to file") delete[] data; return false; } delete[] data; return true; }
bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r) { GSVector4i r = _r ? *_r : GSVector4i(0, 0, m_size.x, m_size.y); // LOTS OF CRAP CODE!!!! PLEASE FIX ME !!! if (m_type == GSTexture::Offscreen) { // The fastest way will be to use a PBO to read the data asynchronously. Unfortunately GSdx // architecture is waiting the data right now. #if 0 // Maybe it is as good as the code below. I don't know // With openGL 4.5 you can use glGetTextureSubImage glGetTextureImage(m_texture_id, GL_TEX_LEVEL_0, m_int_format, m_int_type, 1024*1024*16, m_local_buffer); #else // Bind the texture to the read framebuffer to avoid any disturbance glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0); glPixelStorei(GL_PACK_ALIGNMENT, m_int_alignment); glReadPixels(r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, m_local_buffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); #endif m.bits = m_local_buffer; m.pitch = m_size.x << m_int_shift; return true; } else if (m_type == GSTexture::Texture || m_type == GSTexture::RenderTarget) { GL_PUSH("Upload Texture %d", m_texture_id); // POP is in Unmap m_dirty = true; m_clean = false; uint32 row_byte = r.width() << m_int_shift; uint32 map_size = r.height() * row_byte; m.bits = (uint8*)PboPool::Map(map_size); m.pitch = row_byte; #ifdef ENABLE_OGL_DEBUG_MEM_BW g_real_texture_upload_byte += map_size; #endif // Save the area for the unmap m_r_x = r.x; m_r_y = r.y; m_r_w = r.width(); m_r_h = r.height(); return true; } return false; }
bool GSTextureOGL::Save(const std::string& fn) { // Collect the texture data uint32 pitch = 4 * m_committed_size.x; uint32 buf_size = pitch * m_committed_size.y * 2;// Note *2 for security (depth/stencil) std::unique_ptr<uint8[]> image(new uint8[buf_size]); #ifdef ENABLE_OGL_DEBUG GSPng::Format fmt = GSPng::RGB_A_PNG; #else GSPng::Format fmt = GSPng::RGB_PNG; #endif if (IsBackbuffer()) { glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get()); } else if(IsDss()) { glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0); glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get()); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); fmt = GSPng::RGB_A_PNG; } else if(m_format == GL_R32I) { // Note: 4.5 function used for accurate DATE // barely used outside of dev and not sparse anyway glGetTextureImage(m_texture_id, 0, GL_RED_INTEGER, GL_INT, buf_size, image.get()); fmt = GSPng::R32I_PNG; } else { glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0); if (m_format == GL_RGBA8) { glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get()); } else if (m_format == GL_R16UI) { glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image.get()); fmt = GSPng::R16I_PNG; } else if (m_format == GL_R8) { fmt = GSPng::R8I_PNG; glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RED, GL_UNSIGNED_BYTE, image.get()); } glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } int compression = theApp.GetConfigI("png_compression_level"); return GSPng::Save(fmt, fn, image.get(), m_committed_size.x, m_committed_size.y, pitch, compression); }
void Texture::read(size_t size, void* data) const { GLenum tex_type = toTextureType(type()); SurfaceFormat fmt = this->format(); ImageFormat gl_fmt = toImageFormat(fmt); // Read to 'data', not to a device buffer //glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE); # if defined(VCL_GL_ARB_direct_state_access) glGetTextureImage(_glId, 0, gl_fmt.Format, gl_fmt.Type, (GLsizei)size, data); # else TextureBindPoint bp(tex_type, _glId); if (tex_type != GL_TEXTURE_CUBE_MAP) { # if defined(VCL_GL_EXT_direct_state_access) glGetTextureImageEXT(_glId, tex_type, 0, gl_fmt.Format, gl_fmt.Type, data); # else glGetTexImage(tex_type, 0, gl_fmt.Format, gl_fmt.Type, data); # endif } else { const GLenum faces[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; int pixel_size = Vcl::Graphics::sizeInBytes(fmt); GLsizei w = (GLsizei)width(); GLsizei h = (GLsizei)height(); unsigned char* data_ptr = reinterpret_cast<unsigned char*>(data); for (const auto face : faces) { # if defined(VCL_GL_EXT_direct_state_access) glGetTextureImageEXT(_glId, face, 0, gl_fmt.Format, gl_fmt.Type, data_ptr); # else glGetTexImage(face, 0, gl_fmt.Format, gl_fmt.Type, data_ptr); # endif data_ptr += w * h * pixel_size; } } # endif }
bool kit::Texture::saveToFile(std::string filename) { // Fetch data from GPU unsigned char * data = new unsigned char[(this->m_resolution.x * this->m_resolution.y) * 4]; KIT_GL(glGetTextureImage(this->m_glHandle, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLsizei)(((this->m_resolution.x * this->m_resolution.y) * 4) * sizeof(unsigned char)), &data[0])); stbi_write_set_flip_vertically_on_save(1); // Write data to disk if(stbi_write_tga(filename.c_str(), this->m_resolution.x, this->m_resolution.y, 4, (void*)data) == 0) { KIT_ERR("Failed to write image to file") delete[] data; return false; } delete[] data; return true; }
glm::uvec4 kit::Texture::getPixelUint(glm::vec3 position) { glm::uvec4 returner(0, 0, 0, 0); // Clamp position if (position.x > 1.0f) position.x = 1.0f; if (position.x < 0.0f) position.x = 0.0f; if (position.y > 1.0f) position.y = 1.0f; if (position.y < 0.0f) position.x = 0.0f; if (position.z > 1.0f) position.z = 1.0f; if (position.z < 0.0f) position.x = 0.0f; // Flip Y position.y = 1.0f - position.y; // Get a fragment position glm::uvec3 fragPosition(uint32_t(position.x * float(m_resolution.x)), uint32_t(position.y * float(m_resolution.y)), uint32_t(position.z * float(m_resolution.z))); // Clamp again, because now we are in pixelspace, and we dont really want to be able to pick at 1.0, as that is one pixel outside. Ugly but it works. if (fragPosition.x >= m_resolution.x) fragPosition.x = m_resolution.x - 1; if (fragPosition.y >= m_resolution.y) fragPosition.y = m_resolution.y - 1; uint32_t numUints = m_resolution.x * m_resolution.y * 4; size_t dataSize = numUints * sizeof(uint32_t); std::vector<uint32_t> data(numUints); // Download pixels from the GPU #ifndef KIT_SHITTY_INTEL glGetTextureImage(m_glHandle, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, (GLsizei)dataSize, &data[0]); #else bind(); glGetTexImage(m_type, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]); #endif // Fill the returner returner.x = data[((m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4]; returner.y = data[((m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 1]; returner.z = data[((m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 2]; returner.w = data[((m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 3]; // Return the returner return returner; }
glm::vec4 kit::Texture::getPixelFloat(glm::vec3 position) { glm::vec4 returner(0.0, 0.0, 0.0, 0.0); // Clamp position if (position.x > 1.0f) position.x = 1.0f; if (position.x < 0.0f) position.x = 0.0f; if (position.y > 1.0f) position.y = 1.0f; if (position.y < 0.0f) position.x = 0.0f; if (position.z > 1.0f) position.z = 1.0f; if (position.z < 0.0f) position.x = 0.0f; // Flip Y position.y = 1.0f - position.y; // Get a fragment position glm::uvec3 fragPosition(uint32_t(position.x * float(m_resolution.x)), uint32_t(position.y * float(m_resolution.y)), uint32_t(position.z * float(m_resolution.z))); if (fragPosition.x >= m_resolution.x) fragPosition.x = m_resolution.x - 1; if (fragPosition.y >= m_resolution.y) fragPosition.y = m_resolution.y - 1; uint32_t numFloats = m_resolution.x * m_resolution.y * 4; size_t dataSize = numFloats * sizeof(float); std::vector<float> data(numFloats); // Download pixels from the GPU #ifndef KIT_SHITTY_INTEL glGetTextureImage(m_glHandle, 0, GL_RGBA, GL_FLOAT, (GLsizei)dataSize, &data[0]); #else bind(); glGetTexImage(m_type, 0, GL_RGBA, GL_FLOAT, &data[0]); #endif // Fill the returner returner.x = data[ ( (m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 ]; returner.y = data[ ( (m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 1]; returner.z = data[ ( (m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 2]; returner.w = data[ ( (m_resolution.x * m_resolution.y) * fragPosition.z) + (fragPosition.x + (fragPosition.y * m_resolution.x)) * 4 + 3]; // Return the returner return returner; }
static int test_getteximage(void) { GLubyte compare[4096]; int i; glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE, sizeof(compare), compare); for(i = 0; i < 4096; ++i) { if (data[i] != compare[i]) { printf("GetTextureImage() returns incorrect data in byte %i\n", i); printf(" corresponding to (%i,%i) channel %i\n", i / 64, (i / 4) % 16, i % 4); printf(" expected: %i\n", data[i]); printf(" got: %i\n", compare[i]); return 0; } } return 1; }
enum piglit_result piglit_display(void) { bool pass = true; GLuint name; GLubyte *data = malloc(50 * 50 * 6 * 4 * sizeof(GLubyte)); GLubyte *image = malloc(50 * 50 * 4 * sizeof(GLubyte)); /* Throw some invalid inputs at glGetTextureImage. */ /* Non-gen-ed name */ glGetTextureImage(3, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, data); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); /* Unsupported target. */ glGenTextures(1, &name); glBindTexture(GL_TEXTURE_CUBE_MAP_POSITIVE_X, name); glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, data); pass &= piglit_check_gl_error(GL_INVALID_ENUM); glDeleteTextures(1, &name); /* Unsupported dsa target for non-dsa version. */ glGetTexImage(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); pass &= piglit_check_gl_error(GL_INVALID_ENUM); /* No Storage * * The spec doesn't say what should happen in this case. This is * addressed by Khronos Bug 13223. */ glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &name); glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, data); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); glDeleteTextures(1, &name); /* Insufficient storage * * The spec doesn't say what should happen in this case. This is * addressed by Khronos Bug 13223. */ glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &name); glBindTexture(GL_TEXTURE_CUBE_MAP, name); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, 50, 50, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, 50, 50, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, 50, 50, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); /* Note: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y not set */ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, 50, 50, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, 50, 50, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, data); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); glDeleteTextures(1, &name); /* Trivial, but should work. */ glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &name); glTextureStorage2D(name, 1, GL_RGBA8, 50, 50); glGetTextureImage(name, 0, GL_RGBA, GL_UNSIGNED_BYTE, 50 * 50 * 6 * 4, data); pass &= piglit_check_gl_error(GL_NO_ERROR); return pass ? PIGLIT_PASS : PIGLIT_FAIL; }