void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox) { if (src->mMultisampleCount > 0 && mMultisampleCount == 0) // Resolving MS texture { if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE) BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported."); GLint currentFBO = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO); GLuint readFBO = GLRTTManager::instance().getBlitReadFBO(); GLuint drawFBO = GLRTTManager::instance().getBlitDrawFBO(); // Attach source texture glBindFramebuffer(GL_FRAMEBUFFER, readFBO); src->bindToFramebuffer(0, 0, true); // Attach destination texture glBindFramebuffer(GL_FRAMEBUFFER, drawFBO); bindToFramebuffer(0, 0, true); // Perform blit glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO); glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer(srcBox.left, srcBox.top, srcBox.right, srcBox.bottom, dstBox.left, dstBox.top, dstBox.right, dstBox.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Restore the previously bound FBO glBindFramebuffer(GL_FRAMEBUFFER, currentFBO); } else // Just plain copy { if (mMultisampleCount != src->mMultisampleCount) BS_EXCEPT(InvalidParametersException, "When copying textures their multisample counts must match."); if (mTarget == GL_TEXTURE_3D) // 3D textures can't have arrays so their Z coordinate is handled differently { glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, srcBox.front, mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, dstBox.front, srcBox.getWidth(), srcBox.getHeight(), srcBox.getDepth()); } else { glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, src->mFace, mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, mFace, srcBox.getWidth(), srcBox.getHeight(), 1); } } }
void GlRenderer::copy_rect( uint16_t source_top_left[2], uint16_t target_top_left[2], uint16_t dimensions[2]) { // Draw pending commands this->draw(); uint32_t upscale = this->internal_upscaling; GLint src_x = (GLint) source_top_left[0] * (GLint) upscale; GLint src_y = (GLint) source_top_left[1] * (GLint) upscale; GLint dst_x = (GLint) target_top_left[0] * (GLint) upscale; GLint dst_y = (GLint) target_top_left[1] * (GLint) upscale; GLsizei w = (GLsizei) dimensions[0] * (GLsizei) upscale; GLsizei h = (GLsizei) dimensions[1] * (GLsizei) upscale; // XXX CopyImageSubData gives undefined results if the source // and target area overlap, this should be handled // explicitely /* TODO - OpenGL 4.3 and GLES 3.2 requirement! FIXME! */ glCopyImageSubData( this->fb_out->id, GL_TEXTURE_2D, 0, src_x, src_y, 0, this->fb_out->id, GL_TEXTURE_2D, 0, dst_x, dst_y, 0, w, h, 1 ); get_error(); }
void GFXGLWindowTarget::resolveTo(GFXTextureObject* obj) { AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj); if( gglHasExtension(ARB_copy_image) ) { if(mBackBufferColorTex.getWidth() == glTexture->getWidth() && mBackBufferColorTex.getHeight() == glTexture->getHeight() && mBackBufferColorTex.getFormat() == glTexture->getFormat()) { glCopyImageSubData( static_cast<GFXGLTextureObject*>(mBackBufferColorTex.getPointer())->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, glTexture->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, getSize().x, getSize().y, 1); return; } } PRESERVE_FRAMEBUFFER(); if(!mCopyFBO) { glGenFramebuffers(1, &mCopyFBO); } glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFBO); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture->getHandle(), 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackBufferFBO); glBlitFramebuffer(0, 0, getSize().x, getSize().y, 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); }
/* * * Core in: * OpenGL : 2.0 * OpenGLES : 3.2 */ void rglCopyImageSubData( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES32) glCopyImageSubData(srcName, srcTarget, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); #endif }
Texture2DArray::Texture2DArray(const Texture2DArray& rhs) : Texture(rhs) , dimensions_(rhs.dimensions_) { setTextureParameterFunction(this, &Texture2DArray::default2DArrayTextureParameterFunction); initialize(nullptr); if(OpenGLCapabilities::getOpenGLVersion() >= 430){ //GPU memcpy glCopyImageSubData(rhs.getID(), rhs.getTarget(), 0, 0, 0, 0, getID(), target_, 0, 0, 0, 0, dimensions_.x, dimensions_.y, dimensions_.z); } else{ //Copy data through PBO loadFromPBO(&rhs); } }
static bool test_copy_image(const struct fmt_test *test, GLuint src, GLuint *texture) { bool result = true; GLuint tex = create_texture(test); *texture = tex; glCopyImageSubData(src, GL_TEXTURE_2D, 0, 0, 0, 0, tex, GL_TEXTURE_2D, 0, 0, 0, 0, piglit_width, piglit_height, 0); if (!piglit_check_gl_error(GL_NO_ERROR)) { piglit_report_subtest_result(PIGLIT_FAIL, "format 0x%x copyimage fail", test->iformat); result = false; } return result; }
Texture2DArray& Texture2DArray::operator=(const Texture2DArray& rhs) { if (this != &rhs) { Texture::operator=(rhs); dimensions_ = rhs.dimensions_; setTextureParameterFunction(this, &Texture2DArray::default2DArrayTextureParameterFunction); initialize(nullptr); if(OpenGLCapabilities::getOpenGLVersion() >= 430){ //GPU memcpy glCopyImageSubData(rhs.getID(), rhs.getTarget(), 0, 0, 0, 0, getID(), target_, 0, 0, 0, 0, rhs.dimensions_.x, rhs.dimensions_.y, rhs.dimensions_.z); } else{ //Copy data through PBO loadFromPBO(&rhs); } } return *this; }
static enum piglit_result run_multisample_test(struct texture_format *src_format, struct texture_format *dst_format) { bool pass = true; int fbo_width, fbo_height; GLuint fbo, rb, src_tex, dst_tex, res_tex; static const GLfloat verts[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0 }; /* Upload the source, destination, and expected result */ src_tex = piglit_multisample_texture(GL_TEXTURE_2D_MULTISAMPLE, 0, src_format->internal_format, TEX_SIZE, TEX_SIZE, 1, samples, src_format->format, src_format->data_type, src_data); dst_tex = piglit_multisample_texture(GL_TEXTURE_2D_MULTISAMPLE, 0, dst_format->internal_format, TEX_SIZE, TEX_SIZE, 1, samples, dst_format->format, dst_format->data_type, dst_data); res_tex = piglit_multisample_texture(GL_TEXTURE_2D_MULTISAMPLE, 0, dst_format->internal_format, TEX_SIZE, TEX_SIZE, 1, samples, dst_format->format, dst_format->data_type, res_data); pass &= piglit_check_gl_error(GL_NO_ERROR); /* If any of these are zero, but there was no error, then it must * not be renderable, so we just skip without even reporting the * subtest. */ if ((src_tex == 0 || dst_tex == 0 || res_tex == 0) && pass) return PIGLIT_SKIP; glCopyImageSubData(src_tex, GL_TEXTURE_2D_MULTISAMPLE, 0, TEX_SIZE / 4, TEX_SIZE / 4, 0, dst_tex, GL_TEXTURE_2D_MULTISAMPLE, 0, TEX_SIZE / 4, TEX_SIZE / 4, 0, TEX_SIZE / 2, TEX_SIZE / 2, 1); pass &= piglit_check_gl_error(GL_NO_ERROR); glCopyImageSubData(dst_tex, GL_TEXTURE_2D_MULTISAMPLE, 0, 0, TEX_SIZE / 2, 0, dst_tex, GL_TEXTURE_2D_MULTISAMPLE, 0, TEX_SIZE / 2, 0, 0, TEX_SIZE / 2, TEX_SIZE / 2, 1); pass &= piglit_check_gl_error(GL_NO_ERROR); if (piglit_automatic) { fbo_width = TEX_SIZE; fbo_height = TEX_SIZE; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glGenRenderbuffers(1, &rb); glBindRenderbuffer(GL_RENDERBUFFER, rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, fbo_width, fbo_height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); } else { fbo_width = piglit_width; fbo_height = piglit_height; glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo); } pass &= piglit_check_gl_error(GL_NO_ERROR); glViewport(0, 0, fbo_width, fbo_height); glClearColor(1.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); /* Now we use a comparison shader to check to see if the * destination matches the expected result. */ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, dst_tex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, res_tex); load_compare_program(dst_format); pass &= piglit_check_gl_error(GL_NO_ERROR); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); pass &= piglit_check_gl_error(GL_NO_ERROR); /* If the destination texture matches the expected result, we * should get green. If not, we get red and this test fails. */ pass &= piglit_probe_rect_rgb(0, 0, fbo_width, fbo_height, green); glDeleteTextures(1, &src_tex); glDeleteTextures(1, &dst_tex); glDeleteTextures(1, &res_tex); if (!piglit_automatic) piglit_present_results(); return pass ? PIGLIT_PASS : PIGLIT_FAIL; }
static bool test_simple_errors(GLenum src_target, GLenum dst_target) { bool pass = true; GLuint i, src, src2, dst; src = image_create(src_target); dst = image_create(dst_target); /* Test all three combinations of incomplete src or dst */ glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); image_storage(src_target, src, GL_RGBA8, 32, 32); assert(piglit_check_gl_error(GL_NO_ERROR)); glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); image_storage(dst_target, dst, GL_RGBA8, 32, 32); assert(piglit_check_gl_error(GL_NO_ERROR)); /* We want to test with empty src but valid dst */ src2 = image_create(src_target); glCopyImageSubData(src2, src_target, 0, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); /* This is no longer needed */ image_delete(src_target, src2); /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core * Profile spec says: * * "An INVALID_VALUE error is generated if either name does not * correspond to a valid renderbuffer or texture object according * to the corresponding target parameter." */ if (src_target != GL_RENDERBUFFER_EXT) { for (i = 0; i < ARRAY_LENGTH(targets); ++i) { if (targets[i] == src_target) continue; /* here, targets[i] doesn't match src object's target */ glCopyImageSubData(src, targets[i], 0, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); if (!pass) return false; } } /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core * Profile spec says: * * "An INVALID_VALUE error is generated if either name does not * correspond to a valid renderbuffer or texture object according * to the corresponding target parameter." */ if (dst_target != GL_RENDERBUFFER_EXT) { for (i = 0; i < ARRAY_LENGTH(targets); ++i) { if (targets[i] == dst_target) continue; /* here, targets[i] doesn't match dst object's target */ glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, targets[i], 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); if (!pass) return false; } } /* 4523 should be a bogus renderbuffer/texture */ glCopyImageSubData(4523, src_target, 0, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 0, 0, 0, 4523, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* Invalid level */ glCopyImageSubData(src, src_target, 5, 0, 0, 0, dst, dst_target, 0, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 5, 0, 0, 0, 0, 0, 0); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* Region out of bounds */ glCopyImageSubData(src, src_target, 0, 7, 5, 2, dst, dst_target, 0, 0, 0, 0, 26, 25, 20); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 7, 5, 2, dst, dst_target, 0, 0, 0, 0, 25, 30, 20); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 7, 5, 2, dst, dst_target, 0, 0, 0, 0, 25, 24, 31); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 0, 7, 5, 2, 26, 25, 20); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 0, 7, 5, 2, 25, 30, 20); pass &= piglit_check_gl_error(GL_INVALID_VALUE); glCopyImageSubData(src, src_target, 0, 0, 0, 0, dst, dst_target, 0, 7, 5, 2, 25, 24, 31); pass &= piglit_check_gl_error(GL_INVALID_VALUE); image_delete(src_target, src); image_delete(dst_target, dst); return pass; }
static bool test_compressed_alignment_errors() { bool pass = true; GLuint tex[4]; glGenTextures(4, tex); glBindTexture(GL_TEXTURE_2D, tex[0]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 128); glBindTexture(GL_TEXTURE_2D, tex[1]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA16UI, 32, 32); /* Check for alignment constaints */ /* bad width = 21 */ glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0, tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 21, 24, 1); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* bad height = 22 */ glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0, tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 22, 1); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* bad srcX = 2 */ glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 2, 0, 0, tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 24, 1); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* bad srcY = 1 */ glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 1, 0, tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 24, 1); pass &= piglit_check_gl_error(GL_INVALID_VALUE); /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core * Profile spec says: * * "An INVALID_OPERATION error is generated if the texel size of * the uncompressed image is not equal to the block size of the * compressed image." */ glBindTexture(GL_TEXTURE_2D, tex[2]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB16UI, 32, 32); glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0, tex[2], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 20, 1); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core * Profile spec says: * * "An INVALID_OPERATION error is generated if the formats are * not compatible." * * The definition of compatible refers back to table 8.22 "Compatible * internal formats for TextureView." This table does not contain * S3TC formats because they are from an older extension. Given the * different encodings of DXT1 and DXT3 textures, it is reasonable to * assume they would not be compatible for texture views, and this * matches at least NVIDIA's implementation. */ glBindTexture(GL_TEXTURE_2D, tex[3]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 32, 32); glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0, tex[3], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 20, 1); pass &= piglit_check_gl_error(GL_INVALID_OPERATION); glDeleteTextures(4, tex); return pass; }
PIGLIT_GL_TEST_CONFIG_END static bool test_combination(GLenum intFormat, GLenum srcFormat, GLenum srcType, GLenum dstFormat, GLenum dstType) { const int width = 16, height = 16; int i; GLuint textures[2]; GLubyte *image, *getimage; bool pass = true; int comps; switch (srcFormat) { case GL_RGB: case GL_BGR: comps = 3; break; case GL_RGBA: case GL_BGRA: case GL_RGBA_INTEGER: case GL_BGRA_INTEGER: comps = 4; break; default: assert(!"Unexpected format"); comps = 4; } getimage = malloc(width * height * comps); image = malloc(width * height * comps); if (comps == 4) { for (i = 0; i < width * height; i++) { image[i * 4 + 0] = 0xff; image[i * 4 + 1] = 0x80; image[i * 4 + 2] = 0x40; image[i * 4 + 3] = 0x20; } } else { for (i = 0; i < width * height; i++) { image[i * 3 + 0] = 0xff; image[i * 3 + 1] = 0x80; image[i * 3 + 2] = 0x40; } } glGenTextures(2, textures); /* setup tex0 */ glBindTexture(GL_TEXTURE_2D, textures[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0, srcFormat, srcType, image); /* setup tex1 */ glBindTexture(GL_TEXTURE_2D, textures[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0, dstFormat, dstType, NULL); if (!piglit_check_gl_error(GL_NO_ERROR)) { /* should be no errors */ pass = false; } /* Copy from tex0 to tex1 */ glCopyImageSubData(textures[0], GL_TEXTURE_2D, 0, /* src image */ 0, 0, 0, /* src offset */ textures[1], GL_TEXTURE_2D, 0, /* dst image */ 0, 0, 0, /* dst offset */ width, height, 1); /* src size */ /* Readback tex1 */ glGetTexImage(GL_TEXTURE_2D, 0, srcFormat, srcType, getimage); if (memcmp(image, getimage, width * height * comps) != 0) { printf("Failure:\n"); printf(" internal tex format=%s\n", piglit_get_gl_enum_name(intFormat)); printf(" src tex format=%s type=%s\n", piglit_get_gl_enum_name(srcFormat), piglit_get_gl_enum_name(srcType)); printf(" dst tex format=%s type=%s\n", piglit_get_gl_enum_name(dstFormat), piglit_get_gl_enum_name(dstType)); printf("Expected %u %u %u %u\n", image[0], image[1], image[2], image[3]); printf("Found %u %u %u %u\n", getimage[0], getimage[1], getimage[2], getimage[3]); pass = false; } glDeleteTextures(2, textures); free(image); free(getimage); return pass; }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL43_nglCopyImageSubData(JNIEnv *__env, jclass clazz, jint srcName, jint srcTarget, jint srcLevel, jint srcX, jint srcY, jint srcZ, jint dstName, jint dstTarget, jint dstLevel, jint dstX, jint dstY, jint dstZ, jint srcWidth, jint srcHeight, jint srcDepth, jlong __functionAddress) { glCopyImageSubDataPROC glCopyImageSubData = (glCopyImageSubDataPROC)(intptr_t)__functionAddress; UNUSED_PARAMS(__env, clazz) glCopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); }
bool initTexture() { bool Validated(true); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(texture::MAX, &TextureName[0]); gli::texture2d Texture(gli::load_dds((getDataDirectory() + TEXTURE_DIFFUSE).c_str())); assert(!Texture.empty()); gli::gl GL(gli::gl::PROFILE_GL33); gli::gl::format const Format = GL.translate(Texture.format(), Texture.swizzles()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, TextureName[texture::DIFFUSE]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, GLint(Texture.levels() - 1)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); // Set image for(std::size_t Level = 0; Level < Texture.levels(); ++Level) { glTexImage2D(GL_TEXTURE_2D, GLint(Level), Format.Internal, GLsizei(Texture[Level].extent().x), GLsizei(Texture[Level].extent().y), 0, Format.External, Format.Type, Texture[Level].data()); } // Allocate texture storage of texture::COPY. glBindTexture(GL_TEXTURE_2D, TextureName[texture::COPY]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, GLint(Texture.levels() - 1)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); for(std::size_t Level = 0; Level < Texture.levels(); ++Level) { glTexImage2D(GL_TEXTURE_2D, GLint(Level), Format.Internal, GLsizei(Texture[Level].extent().x), GLsizei(Texture[Level].extent().y), 0, Format.External, Format.Type, nullptr); } glBindTexture(GL_TEXTURE_2D, 0); // Fill texture data of texture::COPY from texture::DIFFUSE. for(std::size_t Level = 0; Level < Texture.levels(); ++Level) { glCopyImageSubData( TextureName[texture::DIFFUSE], GL_TEXTURE_2D, GLint(Level), 0, 0, 0, TextureName[texture::COPY], GL_TEXTURE_2D, GLint(Level), 0, 0, 0, GLsizei(Texture[Level].extent().x), GLsizei(Texture[Level].extent().y), 1); } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); return Validated; }
void GLGSRender::end() { if (skip_frame || !framebuffer_status_valid || (conditional_render_enabled && conditional_render_test_failed) || !check_program_state()) { rsx::thread::end(); return; } if (manually_flush_ring_buffers) { //Use approximations to reseve space. This path is mostly for debug purposes anyway u32 approx_vertex_count = rsx::method_registers.current_draw_clause.get_elements_count(); u32 approx_working_buffer_size = approx_vertex_count * 256; //Allocate 256K heap if we have no approximation at this time (inlined array) m_attrib_ring_buffer->reserve_storage_on_heap(std::max(approx_working_buffer_size, 256 * 1024U)); m_index_ring_buffer->reserve_storage_on_heap(16 * 1024); } //Do vertex upload before RTT prep / texture lookups to give the driver time to push data u32 vertex_draw_count; u32 actual_vertex_count; u32 vertex_base; std::optional<std::tuple<GLenum, u32> > indexed_draw_info; std::tie(vertex_draw_count, actual_vertex_count, vertex_base, indexed_draw_info) = set_vertex_buffer(); std::chrono::time_point<steady_clock> program_start = steady_clock::now(); //Load program here since it is dependent on vertex state load_program(vertex_base, actual_vertex_count); std::chrono::time_point<steady_clock> program_stop = steady_clock::now(); m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count(); if (manually_flush_ring_buffers) { m_attrib_ring_buffer->unmap(); m_index_ring_buffer->unmap(); } else { //DMA push; not needed with MAP_COHERENT //glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); } //Check if depth buffer is bound and valid //If ds is not initialized clear it; it seems new depth textures should have depth cleared auto copy_rtt_contents = [](gl::render_target *surface) { //Copy data from old contents onto this one //1. Clip a rectangular region defning the data //2. Perform a GPU blit u16 parent_w = surface->old_contents->width(); u16 parent_h = surface->old_contents->height(); u16 copy_w, copy_h; std::tie(std::ignore, std::ignore, copy_w, copy_h) = rsx::clip_region<u16>(parent_w, parent_h, 0, 0, surface->width(), surface->height(), true); glCopyImageSubData(surface->old_contents->id(), GL_TEXTURE_2D, 0, 0, 0, 0, surface->id(), GL_TEXTURE_2D, 0, 0, 0, 0, copy_w, copy_h, 1); surface->set_cleared(); surface->old_contents = nullptr; }; //Check if we have any 'recycled' surfaces in memory and if so, clear them std::vector<int> buffers_to_clear; bool clear_all_color = true; bool clear_depth = false; for (int index = 0; index < 4; index++) { if (std::get<0>(m_rtts.m_bound_render_targets[index]) != 0) { if (std::get<1>(m_rtts.m_bound_render_targets[index])->cleared()) clear_all_color = false; else buffers_to_clear.push_back(index); } } gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil); if (ds && !ds->cleared()) { clear_depth = true; } //Temporarily disable pixel tests glDisable(GL_SCISSOR_TEST); if (clear_depth || buffers_to_clear.size() > 0) { GLenum mask = 0; if (clear_depth) { gl_state.depth_mask(GL_TRUE); gl_state.clear_depth(1.0); gl_state.clear_stencil(255); mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; } if (clear_all_color) mask |= GL_COLOR_BUFFER_BIT; glClear(mask); if (buffers_to_clear.size() > 0 && !clear_all_color) { GLfloat colors[] = { 0.f, 0.f, 0.f, 0.f }; //It is impossible for the render target to be typa A or B here (clear all would have been flagged) for (auto &i: buffers_to_clear) glClearBufferfv(draw_fbo.id(), i, colors); } if (clear_depth) gl_state.depth_mask(rsx::method_registers.depth_write_enabled()); ds->set_cleared(); } if (g_cfg.video.strict_rendering_mode) { if (ds->old_contents != nullptr) copy_rtt_contents(ds); for (auto &rtt : m_rtts.m_bound_render_targets) { if (std::get<0>(rtt) != 0) { auto surface = std::get<1>(rtt); if (surface->old_contents != nullptr) copy_rtt_contents(surface); } } } glEnable(GL_SCISSOR_TEST); std::chrono::time_point<steady_clock> textures_start = steady_clock::now(); //Setup textures //Setting unused texture to 0 is not needed, but makes program validation happy if we choose to enforce it for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { int location; if (!rsx::method_registers.fragment_textures[i].enabled()) { if (m_textures_dirty[i]) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); m_textures_dirty[i] = false; } continue; } if (m_program->uniforms.has_location("tex" + std::to_string(i), &location)) { m_gl_textures[i].set_target(get_gl_target_for_texture(rsx::method_registers.fragment_textures[i])); __glcheck m_gl_texture_cache.upload_texture(i, rsx::method_registers.fragment_textures[i], m_gl_textures[i], m_rtts); __glcheck m_gl_sampler_states[i].apply(rsx::method_registers.fragment_textures[i]); } } //Vertex textures for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) { int texture_index = i + rsx::limits::fragment_textures_count; int location; if (!rsx::method_registers.vertex_textures[i].enabled()) { //glActiveTexture(GL_TEXTURE0 + texture_index); //glBindTexture(GL_TEXTURE_2D, 0); continue; } if (m_program->uniforms.has_location("vtex" + std::to_string(i), &location)) { m_gl_vertex_textures[i].set_target(get_gl_target_for_texture(rsx::method_registers.vertex_textures[i])); __glcheck m_gl_texture_cache.upload_texture(texture_index, rsx::method_registers.vertex_textures[i], m_gl_vertex_textures[i], m_rtts); } } std::chrono::time_point<steady_clock> textures_end = steady_clock::now(); m_textures_upload_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count(); std::chrono::time_point<steady_clock> draw_start = steady_clock::now(); if (g_cfg.video.debug_output) { m_program->validate(); } if (indexed_draw_info) { const GLenum index_type = std::get<0>(indexed_draw_info.value()); const u32 index_offset = std::get<1>(indexed_draw_info.value()); if (__glcheck gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART)) { __glcheck glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff); } __glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, index_type, (GLvoid *)(uintptr_t)index_offset); } else { glDrawArrays(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), 0, vertex_draw_count); } m_attrib_ring_buffer->notify(); m_index_ring_buffer->notify(); m_vertex_state_buffer->notify(); m_fragment_constants_buffer->notify(); m_transform_constants_buffer->notify(); std::chrono::time_point<steady_clock> draw_end = steady_clock::now(); m_draw_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(draw_end - draw_start).count(); m_draw_calls++; if (zcull_task_queue.active_query && zcull_task_queue.active_query->active) zcull_task_queue.active_query->num_draws++; synchronize_buffers(); rsx::thread::end(); }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL43_nglCopyImageSubData(JNIEnv *env, jclass clazz, jint srcName, jint srcTarget, jint srcLevel, jint srcX, jint srcY, jint srcZ, jint dstName, jint dstTarget, jint dstLevel, jint dstX, jint dstY, jint dstZ, jint srcWidth, jint srcHeight, jint srcDepth, jlong function_pointer) { glCopyImageSubDataPROC glCopyImageSubData = (glCopyImageSubDataPROC)((intptr_t)function_pointer); glCopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); }
static enum piglit_result run_test(struct texture_format *src_format, struct texture_format *dst_format) { bool pass = true, warn = false; unsigned src_width, src_height, dst_width, dst_height; unsigned src_level, dst_level; GLuint texture[2]; glEnable(GL_TEXTURE_2D); glGenTextures(2, texture); src_width = TEX_SIZE * src_format->block_width; src_height = TEX_SIZE * src_format->block_height; glBindTexture(GL_TEXTURE_2D, texture[0]); if (src_format->can_be_reinterpreted) { src_level = DEFAULT_SRC_LEVEL; glTexStorage2D(GL_TEXTURE_2D, src_level + 2, src_format->internal_format, src_width << src_level, src_height << src_level); if (src_format->block_width != 1 || src_format->block_height != 1) { /* Compressed */ glCompressedTexSubImage2D(GL_TEXTURE_2D, src_level, 0, 0, src_width, src_height, src_format->internal_format, TEX_SIZE * TEX_SIZE * src_format->bytes, src_data); } else { glTexSubImage2D(GL_TEXTURE_2D, src_level, 0, 0, src_width, src_height, src_format->format, src_format->data_type, src_data); } } else { src_level = 0; /* All non-reintepretable textures are uncompressed */ glTexImage2D(GL_TEXTURE_2D, 0, src_format->internal_format, src_width, src_height, 0, src_format->format, src_format->data_type, src_data); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); pass &= piglit_check_gl_error(GL_NO_ERROR); if (!pass) goto cleanup; warn |= !check_texture(texture[0], src_level, src_format, src_data); dst_width = TEX_SIZE * dst_format->block_width; dst_height = TEX_SIZE * dst_format->block_height; glBindTexture(GL_TEXTURE_2D, texture[1]); if (dst_format->can_be_reinterpreted) { dst_level = DEFAULT_DST_LEVEL; glTexStorage2D(GL_TEXTURE_2D, dst_level + 2, dst_format->internal_format, dst_width << dst_level, dst_height << dst_level); if (dst_format->block_width != 1 || dst_format->block_height != 1) { /* Compressed */ glCompressedTexSubImage2D(GL_TEXTURE_2D, dst_level, 0, 0, dst_width, dst_height, dst_format->internal_format, TEX_SIZE * TEX_SIZE * dst_format->bytes, dst_data); } else { glTexSubImage2D(GL_TEXTURE_2D, dst_level, 0, 0, dst_width, dst_height, dst_format->format, dst_format->data_type, dst_data); } } else { dst_level = 0; /* All non-reintepritable textures are uncompressed */ glTexImage2D(GL_TEXTURE_2D, 0, dst_format->internal_format, dst_width, dst_height, 0, dst_format->format, dst_format->data_type, dst_data); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); pass &= piglit_check_gl_error(GL_NO_ERROR); if (!pass) goto cleanup; warn |= !check_texture(texture[1], dst_level, dst_format, dst_data); glCopyImageSubData(texture[0], GL_TEXTURE_2D, src_level, src_width / 4, src_height / 4, 0, texture[1], GL_TEXTURE_2D, dst_level, dst_width / 4, dst_height / 4, 0, src_width / 2, src_height / 2, 1); pass &= piglit_check_gl_error(GL_NO_ERROR); glCopyImageSubData(texture[1], GL_TEXTURE_2D, dst_level, 0, dst_height / 2, 0, texture[1], GL_TEXTURE_2D, dst_level, dst_width / 2, 0, 0, dst_width / 2, dst_height / 2, 1); pass &= piglit_check_gl_error(GL_NO_ERROR); pass &= check_texture(texture[1], dst_level, dst_format, res_data); cleanup: glDeleteTextures(2, texture); glDisable(GL_TEXTURE_2D); return pass ? (warn ? PIGLIT_WARN : PIGLIT_PASS) : PIGLIT_FAIL; }
/** * Create a 3D texture of the given format and size, draw a textured quad * with that texture, and check results. */ static bool test_render(GLenum internalFormat, int width, int height, int depth) { static const float c1[4] = {0.25, 0.25, 0.25, 1.0}; static const float c2[4] = {0.75, 0.75, 0.75, 1.0}; bool pass = true; char *data; int i, j; GLuint tex; unsigned mbytes = tex_size(internalFormat, width, height, depth); printf("Testing %d x %d x %d %s (%u MB) texture\n", width, height, depth, piglit_get_gl_enum_name(internalFormat), mbytes); fflush(stdout); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_3D, tex); alloc_tex3d(GL_TEXTURE_3D, internalFormat, width, height, depth); if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("Creating texture failed in test_render().\n"); pass = false; goto end; } /* Set its pixels, slice by slice. */ data = malloc(width * height * 4); for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { int a = (j * width + i) * 4; data[a+0] = data[a+1] = data[a+2] = data[a+3] = (i * 255) / (width - 1); } } if (piglit_is_extension_supported("GL_ARB_copy_image")) { /* load 0th slice */ glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); /* copy 0th slice to other slices (should be faster) */ for (i = 1; i < depth; i++) { glCopyImageSubData(tex, GL_TEXTURE_3D, 0, 0, 0, 0, tex, GL_TEXTURE_3D, 0, 0, 0, i, width, height, 1); } } else { /* load each slice with glTexSubImage3D */ for (i = 0; i < depth; i++) { glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); } } free(data); glClear(GL_COLOR_BUFFER_BIT); /* Now try basic rendering. */ glEnable(GL_TEXTURE_3D); glBegin(GL_QUADS); glTexCoord3f(0, 0, 0.5); glVertex2f(0, 0); glTexCoord3f(0, 1, 0.5); glVertex2f(0, piglit_height); glTexCoord3f(1, 1, 0.5); glVertex2f(piglit_width, piglit_height); glTexCoord3f(1, 0, 0.5); glVertex2f(piglit_width, 0); glEnd(); pass = piglit_probe_pixel_rgb(piglit_width * 1 / 4, piglit_height * 1 / 4, c1) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 3 / 4, piglit_height * 1 / 4, c2) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 1 / 4, piglit_height * 3 / 4, c1) && pass; pass = piglit_probe_pixel_rgb(piglit_width * 3 / 4, piglit_height * 3 / 4, c2) && pass; piglit_present_results(); if (!pass) { printf("rendering failed with %d x %d x %d %s texture\n", width, height, depth, piglit_get_gl_enum_name(internalFormat)); } end: glDeleteTextures(1, &tex); return pass; }
JNIEXPORT void JNICALL Java_org_lwjgl_opengles_GLES32_glCopyImageSubData(JNIEnv *__env, jclass clazz, jint srcName, jint srcTarget, jint srcLevel, jint srcX, jint srcY, jint srcZ, jint dstName, jint dstTarget, jint dstLevel, jint dstX, jint dstY, jint dstZ, jint srcWidth, jint srcHeight, jint srcDepth) { glCopyImageSubDataPROC glCopyImageSubData = (glCopyImageSubDataPROC)tlsGetFunction(315); UNUSED_PARAM(clazz) glCopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); }
void OGLTexture1D::CopyToSubTexture1D(Texture& target, uint32_t dst_array_index, uint32_t dst_level, uint32_t dst_x_offset, uint32_t dst_width, uint32_t src_array_index, uint32_t src_level, uint32_t src_x_offset, uint32_t src_width) { BOOST_ASSERT(type_ == target.Type()); if ((format_ == target.Format()) && !IsCompressedFormat(format_) && (glloader_GL_VERSION_4_3() || glloader_GL_ARB_copy_image()) && (src_width == dst_width) && (1 == sample_count_)) { OGLTexture& ogl_target = *checked_cast<OGLTexture*>(&target); glCopyImageSubData( texture_, target_type_, src_level, src_x_offset, 0, src_array_index, ogl_target.GLTexture(), ogl_target.GLType(), dst_level, dst_x_offset, 0, dst_array_index, src_width, 1, 1); } else { OGLRenderEngine& re = *checked_cast<OGLRenderEngine*>(&Context::Instance().RenderFactoryInstance().RenderEngineInstance()); if ((sample_count_ > 1) && !IsCompressedFormat(format_) && (glloader_GL_ARB_texture_rg() || (4 == NumComponents(format_)))) { GLuint fbo_src, fbo_dst; re.GetFBOForBlit(fbo_src, fbo_dst); GLuint old_fbo = re.BindFramebuffer(); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_src); if (array_size_ > 1) { glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_, src_level, src_array_index); } else { if (sample_count_ <= 1) { glFramebufferTexture1D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target_type_, texture_, src_level); } else { glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, texture_); } } OGLTexture& ogl_target = *checked_cast<OGLTexture*>(&target); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_dst); if (array_size_ > 1) { glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ogl_target.GLTexture(), dst_level, dst_array_index); } else { glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target_type_, ogl_target.GLTexture(), dst_level); } glBlitFramebuffer(src_x_offset, 0, src_x_offset + src_width, 1, dst_x_offset, 0, dst_x_offset + dst_width, 1, GL_COLOR_BUFFER_BIT, (src_width == dst_width) ? GL_NEAREST : GL_LINEAR); re.BindFramebuffer(old_fbo, true); } else { if ((src_width == dst_width) && (format_ == target.Format())) { if (IsCompressedFormat(format_)) { BOOST_ASSERT(0 == (src_x_offset & 0x3)); BOOST_ASSERT(0 == (dst_x_offset & 0x3)); BOOST_ASSERT(0 == (src_width & 0x3)); BOOST_ASSERT(0 == (dst_width & 0x3)); Texture::Mapper mapper_src(*this, src_array_index, src_level, TMA_Read_Only, 0, this->Width(src_level)); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, 0, target.Width(dst_level)); uint32_t const block_size = NumFormatBytes(format_) * 4; uint8_t const * s = mapper_src.Pointer<uint8_t>() + (src_x_offset / 4 * block_size); uint8_t* d = mapper_dst.Pointer<uint8_t>() + (dst_x_offset / 4 * block_size); std::memcpy(d, s, src_width / 4 * block_size); } else { size_t const format_size = NumFormatBytes(format_); Texture::Mapper mapper_src(*this, src_array_index, src_level, TMA_Read_Only, src_x_offset, src_width); Texture::Mapper mapper_dst(target, dst_array_index, dst_level, TMA_Write_Only, dst_x_offset, dst_width); uint8_t const * s = mapper_src.Pointer<uint8_t>(); uint8_t* d = mapper_dst.Pointer<uint8_t>(); std::memcpy(d, s, src_width * format_size); } } else { this->ResizeTexture1D(target, dst_array_index, dst_level, dst_x_offset, dst_width, src_array_index, src_level, src_x_offset, src_width, true); } } } }
int OgreOculus::go(void) { // Create Root object root = new Ogre::Root("plugin.cfg", "ogre.cfg"); // OpenGL root->loadPlugin("RenderSystem_GL_d"); root->setRenderSystem(root->getRenderSystemByName("OpenGL Rendering Subsystem")); // Initialize Root root->initialise(false); // Initialize Oculus ovrHmd hmd; ovrHmdDesc hmdDesc; ovrGraphicsLuid luid; ovr_Initialize(nullptr); if(ovr_Create(&hmd, &luid) != ovrSuccess) exit(-1); hmdDesc = ovr_GetHmdDesc(hmd); if(ovr_ConfigureTracking(hmd, ovrTrackingCap_Orientation |ovrTrackingCap_MagYawCorrection |ovrTrackingCap_Position, 0) != ovrSuccess) exit(-2); // Turn off HUD ovr_SetInt(hmd, "PerfHudMode", ovrPerfHud_Off); // Create a window window = root->createRenderWindow("Ogre + Oculus = <3", hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2, false); // Create scene manager and cameras smgr = root->createSceneManager(Ogre::ST_GENERIC); // Load Ogre resource paths from config file Ogre::ConfigFile cf; cf.load("resources_d.cfg"); // Go through all sections & settings in the file and add resources Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); Ogre::String secName, typeName, archName; while (seci.hasMoreElements()) { secName = seci.peekNextKey(); Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName); } } // Set resources Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5); Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // Create the model itself via OgreModel.cpp createOgreModel(smgr); // Create camera createCamera(); // Set viewport and background color Ogre::Viewport* vp = window->addViewport(mCamera); vp->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); // Yellow // Set aspect ratio mCamera->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight())); // Initialize glew if(glewInit() != GLEW_OK) exit(-3); // Get texture sizes ovrSizei texSizeL, texSizeR; texSizeL = ovr_GetFovTextureSize(hmd, ovrEye_Left, hmdDesc.DefaultEyeFov[left], 1); texSizeR = ovr_GetFovTextureSize(hmd, ovrEye_Right, hmdDesc.DefaultEyeFov[right], 1); // Calculate render buffer size ovrSizei bufferSize; bufferSize.w = texSizeL.w + texSizeR.w; bufferSize.h = max(texSizeL.h, texSizeR.h); // Create render texture set ovrSwapTextureSet* textureSet; if(ovr_CreateSwapTextureSetGL(hmd, GL_RGB, bufferSize.w, bufferSize.h, &textureSet) != ovrSuccess) exit(-4); // Create Ogre render texture Ogre::GLTextureManager* textureManager = static_cast<Ogre::GLTextureManager*>(Ogre::GLTextureManager::getSingletonPtr()); Ogre::TexturePtr rtt_texture(textureManager->createManual("RttTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, bufferSize.w, bufferSize.h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET)); Ogre::RenderTexture* rttEyes = rtt_texture->getBuffer(0, 0)->getRenderTarget(); Ogre::GLTexture* gltex = static_cast<Ogre::GLTexture*>(Ogre::GLTextureManager::getSingleton().getByName("RttTex").getPointer()); GLuint renderTextureID = gltex->getGLID(); // Put camera viewport on the ogre render texture Ogre::Viewport* vpts[nbEyes]; vpts[left]=rttEyes->addViewport(cams[left], 0, 0, 0, 0.5f); vpts[right]=rttEyes->addViewport(cams[right], 1, 0.5f, 0, 0.5f); vpts[left]->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); // Black background vpts[right]->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); ovrTexture* mirrorTexture; if(ovr_CreateMirrorTextureGL(hmd, GL_RGB, hmdDesc.Resolution.w, hmdDesc.Resolution.h, &mirrorTexture) != ovrSuccess) exit(-5); Ogre::TexturePtr mirror_texture(textureManager->createManual("MirrorTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, hmdDesc.Resolution.w, hmdDesc.Resolution.h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET)); // Get GLIDs GLuint ogreMirrorTextureID = static_cast<Ogre::GLTexture*>(Ogre::GLTextureManager::getSingleton().getByName("MirrorTex").getPointer())->getGLID(); GLuint oculusMirrorTextureID = ((ovrGLTexture*)mirrorTexture)->OGL.TexId; // Create EyeRenderDesc ovrEyeRenderDesc EyeRenderDesc[nbEyes]; EyeRenderDesc[left] = ovr_GetRenderDesc(hmd, ovrEye_Left, hmdDesc.DefaultEyeFov[left]); EyeRenderDesc[right] = ovr_GetRenderDesc(hmd, ovrEye_Right, hmdDesc.DefaultEyeFov[right]); // Get offsets ovrVector3f offset[nbEyes]; offset[left]=EyeRenderDesc[left].HmdToEyeViewOffset; offset[right]=EyeRenderDesc[right].HmdToEyeViewOffset; // Compositor layer ovrLayerEyeFov layer; layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = 0; layer.ColorTexture[left] = textureSet; layer.ColorTexture[right] = textureSet; layer.Fov[left] = EyeRenderDesc[left].Fov; layer.Fov[right] = EyeRenderDesc[right].Fov; layer.Viewport[left] = OVR::Recti(0, 0, bufferSize.w/2, bufferSize.h); layer.Viewport[right] = OVR::Recti(bufferSize.w/2, 0, bufferSize.w/2, bufferSize.h); // Get projection matrices for(size_t eyeIndex(0); eyeIndex < ovrEye_Count; eyeIndex++) { // Get the projection matrix OVR::Matrix4f proj = ovrMatrix4f_Projection(EyeRenderDesc[eyeIndex].Fov, static_cast<float>(0.01f), 4000, true); // Convert it to Ogre matrix Ogre::Matrix4 OgreProj; for(size_t x(0); x < 4; x++) for(size_t y(0); y < 4; y++) OgreProj[x][y] = proj.M[x][y]; // Set the matrix cams[eyeIndex]->setCustomProjectionMatrix(true, OgreProj); } // Variables for render loop bool render(true); ovrFrameTiming hmdFrameTiming; ovrTrackingState ts; OVR::Posef pose; ovrLayerHeader* layers; // Create event listener for handling user input createEventListener(); //Run physics loop in a new thread std::map<Ogre::Entity*, Ogre::Vector3> positionRequests; std::map<Ogre::Entity*, std::string> animationRequests; std::map<Ogre::Entity*, std::vector<int>> rotationRequests; std::map<std::string, std::string> message; std::thread physicsThread(physicsLoop, smgr, &message, &positionRequests, &animationRequests, &rotationRequests); // Render loop while(render) { // Suspend physics loop and perform requested movement/rotations/animations if(positionRequests.size() > 0 || animationRequests.size() > 0 || rotationRequests.size() > 0){ message.insert(std::pair<std::string, std::string>("", "")); for(auto const &request : positionRequests) { Ogre::Vector3 pos = request.second; Ogre::SceneNode* sceneNode = request.first->getParentSceneNode(); sceneNode->setPosition(pos); } for(auto const &request : animationRequests) { request.first->getAnimationState(request.second)->addTime(0.1); } for(auto const &request : rotationRequests) { Ogre::SceneNode* sceneNode = request.first->getParentSceneNode(); sceneNode->roll(Ogre::Degree(request.second[0])); sceneNode->pitch(Ogre::Degree(request.second[1])); sceneNode->yaw(Ogre::Degree(request.second[2])); } positionRequests.clear(); animationRequests.clear(); rotationRequests.clear(); // Resume physics loop message.clear(); } // Update Ogre window Ogre::WindowEventUtilities::messagePump(); // Advance textureset index textureSet->CurrentIndex = (textureSet->CurrentIndex + 1) % textureSet->TextureCount; // Capture user input mKeyboard->capture(); mMouse->capture(); // Movement calculations mPlayerNode->translate(mDirection, Ogre::Node::TS_LOCAL); hmdFrameTiming = ovr_GetFrameTiming(hmd, 0); ts = ovr_GetTrackingState(hmd, hmdFrameTiming.DisplayMidpointSeconds); pose = ts.HeadPose.ThePose; ovr_CalcEyePoses(pose, offset, layer.RenderPose); oculusOrient = pose.Rotation; oculusPos = pose.Translation; mHeadNode->setOrientation(Ogre::Quaternion(oculusOrient.w, oculusOrient.x, oculusOrient.y, oculusOrient.z) * initialOculusOrientation.Inverse()); // Apply head tracking mHeadNode->setPosition(headPositionTrackingSensitivity * Ogre::Vector3(oculusPos.x, oculusPos.y,oculusPos.z)); // Update Ogre viewports root->_fireFrameRenderingQueued(); vpts[left]->update(); vpts[right]->update(); // Copy the rendered image to the Oculus Swap Texture glCopyImageSubData(renderTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, ((ovrGLTexture*)(&textureSet->Textures[textureSet->CurrentIndex]))->OGL.TexId, GL_TEXTURE_2D, 0, 0, 0, 0, bufferSize.w,bufferSize.h, 1); layers = &layer.Header; // Submit new frame to the Oculus and update window ovr_SubmitFrame(hmd, 0, nullptr, &layers, 1); window->update(); // Exit loop when window is closed if(window->isClosed()) render = false; } // Shud down Oculus ovr_Destroy(hmd); ovr_Shutdown(); // Delete Ogre root and return delete root; return EXIT_SUCCESS; }