static bool set_target(device_t device, texture_t tex, int side, zstencil_t zs) { struct fbo_info *fbo; if (device->cur_render_target == tex && device->cur_zstencil_buffer == zs && device->cur_render_side == side) return true; device->cur_render_target = tex; device->cur_render_side = side; device->cur_zstencil_buffer = zs; if (!tex) return set_current_fbo(device, NULL); fbo = get_fbo(device, tex); if (!fbo) return false; set_current_fbo(device, fbo); if (!attach_rendertarget(fbo, tex, side)) return false; if (!attach_zstencil(fbo, zs)) return false; return true; }
int GlslManager::render_frame_texture(mlt_service service, mlt_frame frame, int width, int height, uint8_t **image) { EffectChain* chain = get_chain( service ); if (!chain) return 1; glsl_fbo fbo = get_fbo( width, height ); if (!fbo) return 1; glsl_texture texture = get_texture( width, height, GL_RGBA ); if (!texture) { release_fbo( fbo ); return 1; } glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); render_fbo( service, chain, fbo->fbo, width, height ); glFinish(); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); release_fbo( fbo ); *image = (uint8_t*) &texture->texture; mlt_frame_set_image( frame, *image, 0, NULL ); mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL ); return 0; }
static inline struct fbo_info *get_fbo_by_tex(struct gs_device *device, gs_texture_t tex) { uint32_t width, height; if (!get_tex_dimensions(tex, &width, &height)) return NULL; return get_fbo(device, width, height, tex->format); }
/* Apparently for mac, PBOs won't do an asynchronous transfer unless you use * FBOs aong with glReadPixels, which is really dumb. */ void device_stage_texture(device_t device, stagesurf_t dst, texture_t src) { struct gs_texture_2d *tex2d = (struct gs_texture_2d*)src; struct fbo_info *fbo; GLint last_fbo; bool success = false; if (!can_stage(dst, tex2d)) goto failed; if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer)) goto failed; fbo = get_fbo(device, dst->width, dst->height, dst->format); if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo)) goto failed_unbind_buffer; if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo)) goto failed_unbind_buffer; glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, src->gl_target, src->texture, 0); if (!gl_success("glFrameBufferTexture2D")) goto failed_unbind_all; glReadPixels(0, 0, dst->width, dst->height, dst->gl_format, dst->gl_type, 0); if (!gl_success("glReadPixels")) goto failed_unbind_all; success = true; failed_unbind_all: gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo); failed_unbind_buffer: gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0); failed: if (!success) blog(LOG_ERROR, "device_stage_texture (GL) failed"); }
int GlslManager::render_frame_rgba(mlt_service service, mlt_frame frame, int width, int height, uint8_t **image) { EffectChain* chain = get_chain( service ); if (!chain) return 1; glsl_fbo fbo = get_fbo( width, height ); if (!fbo) return 1; glsl_texture texture = get_texture( width, height, GL_RGBA ); if (!texture) { release_fbo( fbo ); return 1; } // Use a PBO to hold the data we read back with glReadPixels(). // (Intel/DRI goes into a slow path if we don't read to PBO.) int img_size = width * height * 4; glsl_pbo pbo = get_pbo( img_size ); if (!pbo) { release_fbo( fbo ); release_texture(texture); return 1; } // Set the FBO check_error(); glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); render_fbo( service, chain, fbo->fbo, width, height ); // Read FBO into PBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo ); check_error(); glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ ); check_error(); glReadPixels( 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) ); check_error(); // Copy from PBO uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY ); check_error(); *image = (uint8_t*) mlt_pool_alloc( img_size ); mlt_frame_set_image( frame, *image, img_size, mlt_pool_release ); memcpy( *image, buf, img_size ); // Convert BGRA to RGBA register uint8_t *p = *image; register int n = width * height + 1; while ( --n ) { uint8_t b = p[0]; *p = p[2]; p += 2; *p = b; p += 2; } // Release PBO and FBO glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); glBindTexture( GL_TEXTURE_2D, 0 ); check_error(); mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL); release_fbo( fbo ); return 0; }
void ContextPoolContext::setup_for_pass(const ShaderPass &pass, const RenderOuputGroup& output) { // TODO Capture state object and bind if exists? const RenderTarget& target = output.get_render_target(pass.out); if (pass.in >= 0) { const RenderTarget& in_target = output.get_render_target(pass.in); for (size_t i = 1; i <= in_target.num_attachments; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, in_target.attachments[i - 1]); } } gl->glBindFramebuffer(GL_FRAMEBUFFER, get_fbo(target)); GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5}; gl->glDrawBuffers(target.num_attachments, buffers); gl->glViewport(0, 0, target.width, target.height); if (pass.color_mask) { gl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } else { gl->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } if (pass.depth_mask) { gl->glDepthMask(GL_TRUE); } else { gl->glDepthMask(GL_FALSE); } if (pass.stencil_mask) { gl->glStencilMask(GL_TRUE); } else { gl->glStencilMask(GL_FALSE); } if (pass.depth_func == ShaderPass::DISABLED) { gl->glDisable(GL_DEPTH_TEST); } else { gl->glEnable(GL_DEPTH_TEST); gl->glDepthFunc(pass.depth_func); } if (pass.cull_face == ShaderPass::DISABLED) { gl->glDisable(GL_CULL_FACE); } else { gl->glEnable(GL_CULL_FACE); gl->glCullFace(pass.cull_face); } if (pass.blend_equation == ShaderPass::DISABLED) { gl->glDisable(GL_BLEND); } else { gl->glEnable(GL_BLEND); gl->glBlendEquation(pass.blend_equation); gl->glBlendFunc(pass.blend_src, pass.blend_dst); } if (pass.stencil_func == ShaderPass::DISABLED) { gl->glDisable(GL_STENCIL_TEST); } else { gl->glEnable(GL_STENCIL_TEST); gl->glStencilFunc(pass.stencil_func, 0, 0); //gl->glStencilOpSeparate(GL_BACK, , , ); //gl->glStencilOpSeparate(GL_FRONT, , , ); } if (pass.clear != ShaderPass::DISABLED) { gl->glClear(pass.clear); } }