/* * R_BlitTextureToScrFbo */ static void R_BlitTextureToScrFbo( const refdef_t *fd, image_t *image, int dstFbo, int program_type, const vec4_t color, int blendMask ) { int x, y; int w, h; RB_BindFrameBufferObject( dstFbo ); if( !dstFbo ) { // default framebuffer // set the viewport to full resolution // but keep the scissoring region x = fd->x; y = fd->y; w = fd->width; h = fd->height; RB_Viewport( 0, 0, glConfig.width, glConfig.height ); RB_Scissor( rn.scissor[0], rn.scissor[1], rn.scissor[2], rn.scissor[3] ); } else { // aux framebuffer // set the viewport to full resolution of the framebuffer // set scissor to default framebuffer resolution x = 0; y = 0; w = rf.frameBufferWidth; h = rf.frameBufferHeight; RB_Viewport( 0, 0, w, h ); RB_Scissor( 0, 0, glConfig.width, glConfig.height ); } // blit + flip R_DrawStretchQuick( x, y, w, h, (float)(x)/image->upload_width, 1.0 - (float)(y)/image->upload_height, (float)(x+w)/image->upload_width, 1.0 - (float)(y+h)/image->upload_height, color, program_type, image, blendMask ); // restore 2D viewport and scissor RB_Viewport( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); RB_Scissor( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); }
/* * R_BlitTextureToScrFbo */ static void R_BlitTextureToScrFbo( const refdef_t *fd, image_t *image, int dstFbo, int program_type, const vec4_t color, int blendMask, int numShaderImages, image_t **shaderImages ) { int x, y; int w, h, fw, fh; static char s_name[] = "$builtinpostprocessing"; static shaderpass_t p; static shader_t s; int i; static tcmod_t tcmod; mat4_t m; assert( rsh.postProcessingVBO ); // blit + flip using a static mesh to avoid redundant buffer uploads // (also using custom PP effects like FXAA with the stream VBO causes // Adreno to mark the VBO as "slow" (due to some weird bug) // for the rest of the frame and drop FPS to 10-20). RB_FlushDynamicMeshes(); RB_BindFrameBufferObject( dstFbo ); if( !dstFbo ) { // default framebuffer // set the viewport to full resolution // but keep the scissoring region x = fd->x; y = fd->y; w = fw = fd->width; h = fh = fd->height; RB_Viewport( 0, 0, glConfig.width, glConfig.height ); RB_Scissor( rn.scissor[0], rn.scissor[1], rn.scissor[2], rn.scissor[3] ); } else { // aux framebuffer // set the viewport to full resolution of the framebuffer (without the NPOT padding if there's one) // draw quad on the whole framebuffer texture // set scissor to default framebuffer resolution image_t *cb = RFB_GetObjectTextureAttachment( dstFbo, false ); x = 0; y = 0; w = fw = rf.frameBufferWidth; h = fh = rf.frameBufferHeight; if( cb ) { fw = cb->upload_width; fh = cb->upload_height; } RB_Viewport( 0, 0, w, h ); RB_Scissor( 0, 0, glConfig.width, glConfig.height ); } s.vattribs = VATTRIB_POSITION_BIT|VATTRIB_TEXCOORDS_BIT; s.sort = SHADER_SORT_NEAREST; s.numpasses = 1; s.name = s_name; s.passes = &p; p.rgbgen.type = RGB_GEN_IDENTITY; p.alphagen.type = ALPHA_GEN_IDENTITY; p.tcgen = TC_GEN_NONE; p.images[0] = image; for( i = 0; i < numShaderImages; i++ ) p.images[i + 1] = shaderImages[i]; p.flags = blendMask; p.program_type = program_type; if( !dstFbo ) { tcmod.type = TC_MOD_TRANSFORM; tcmod.args[0] = ( float )( w ) / ( float )( image->upload_width ); tcmod.args[1] = ( float )( h ) / ( float )( image->upload_height ); tcmod.args[4] = ( float )( x ) / ( float )( image->upload_width ); tcmod.args[5] = ( float )( image->upload_height - h - y ) / ( float )( image->upload_height ); p.numtcmods = 1; p.tcmods = &tcmod; } else { p.numtcmods = 0; } Matrix4_Identity( m ); Matrix4_Scale2D( m, fw, fh ); Matrix4_Translate2D( m, x, y ); RB_LoadObjectMatrix( m ); RB_BindShader( NULL, &s, NULL ); RB_BindVBO( rsh.postProcessingVBO->index, GL_TRIANGLES ); RB_DrawElements( 0, 4, 0, 6, 0, 0, 0, 0 ); RB_LoadObjectMatrix( mat4x4_identity ); // restore 2D viewport and scissor RB_Viewport( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); RB_Scissor( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight ); }
/* * R_ResampleCinematicFrame */ static image_t *R_ResampleCinematicFrame( r_cinhandle_t *handle ) { const int samples = 4; if( !handle->pic ) { // we haven't yet read a new frame, return whatever image we got // this will return NULL until at least one frame has been read return handle->image; } if( handle->yuv ) { int i; if( !handle->yuv_images[0] ) { qbyte *fake_data[1] = { NULL }; const char *letters[3] = { "y", "u", "v" }; for( i = 0; i < 3; i++ ) { handle->yuv_images[i] = R_LoadImage( va( "%s_%s", handle->name, letters[i] ), fake_data, 1, 1, IT_CINEMATIC|IT_LUMINANCE, 1 ); } handle->new_frame = qtrue; } if( handle->new_frame ) { int fbo; qboolean in2D; // render/convert three 8-bit YUV images into RGB framebuffer in2D = rf.in2D; fbo = RFB_BoundObject(); if( !in2D ) { R_PushRefInst(); } R_InitViewportTexture( &handle->image, handle->name, 0, handle->cyuv->image_width, handle->cyuv->image_height, 0, IT_CINEMATIC|IT_FRAMEBUFFER, samples ); R_BindFrameBufferObject( handle->image->fbo ); R_Set2DMode( qtrue ); RB_Scissor( 0, 0, handle->image->upload_width, handle->image->upload_height ); RB_Viewport( 0, 0, handle->image->upload_width, handle->image->upload_height ); // flip the image vertically because we're rendering to a FBO R_DrawStretchRawYUVBuiltin( 0, 0, handle->image->upload_width, handle->image->upload_height, (float)handle->cyuv->x_offset / handle->cyuv->image_width, (float)handle->cyuv->y_offset / handle->cyuv->image_height, (float)(handle->cyuv->x_offset + handle->cyuv->width) / handle->cyuv->image_width, (float)(handle->cyuv->y_offset + handle->cyuv->height) / handle->cyuv->image_height, handle->cyuv->yuv, handle->yuv_images, 2 ); if( !in2D ) { R_PopRefInst( 0 ); } R_BindFrameBufferObject( fbo ); R_Set2DMode( in2D ); handle->new_frame = qfalse; } } else { if( !handle->image ) { handle->image = R_LoadImage( handle->name, &handle->pic, handle->width, handle->height, IT_CINEMATIC, samples ); handle->new_frame = qfalse; } else if( handle->new_frame ) { R_ReplaceImage( handle->image, &handle->pic, handle->width, handle->height, handle->image->flags, samples ); handle->new_frame = qfalse; } } return handle->image; }
/* * R_UploadCinematicFrame */ static void R_UploadCinematicFrame( r_cinhandle_t *handle ) { const int samples = 4; ri.Mutex_Lock( handle->lock ); if( !handle->cin || !handle->pic ) { ri.Mutex_Unlock( handle->lock ); return; } if( handle->yuv ) { int i; if( !handle->yuv_images[0] ) { char tn[256]; uint8_t *fake_data[1] = { NULL }; const char *letters[3] = { "y", "u", "v" }; for( i = 0; i < 3; i++ ) { handle->yuv_images[i] = R_LoadImage( va_r( tn, sizeof( tn ), "%s_%s", handle->name, letters[i] ), fake_data, 1, 1, IT_SPECIAL | IT_NO_DATA_SYNC, 1, IMAGE_TAG_GENERIC, 1 ); } handle->new_frame = true; } if( handle->new_frame ) { bool multiSamples2D; bool in2D; // render/convert three 8-bit YUV images into RGB framebuffer in2D = rf.twoD.enabled; multiSamples2D = rf.twoD.multiSamples; if( in2D ) { R_End2D(); } else { R_PushRefInst(); } R_InitViewportTexture( &handle->image, handle->name, 0, handle->cyuv->image_width, handle->cyuv->image_height, 0, IT_SPECIAL | IT_FRAMEBUFFER, IMAGE_TAG_GENERIC, samples ); R_BindFrameBufferObject( handle->image->fbo ); R_SetupGL2D(); RB_Scissor( 0, 0, handle->image->upload_width, handle->image->upload_height ); RB_Viewport( 0, 0, handle->image->upload_width, handle->image->upload_height ); R_UploadRawYUVPic( handle->yuv_images, handle->cyuv->yuv ); // flip the image vertically because we're rendering to a FBO R_DrawStretchRawYUVBuiltin( 0, 0, handle->image->upload_width, handle->image->upload_height, (float)handle->cyuv->x_offset / handle->cyuv->image_width, (float)handle->cyuv->y_offset / handle->cyuv->image_height, (float)( handle->cyuv->x_offset + handle->cyuv->width ) / handle->cyuv->image_width, (float)( handle->cyuv->y_offset + handle->cyuv->height ) / handle->cyuv->image_height, handle->yuv_images, 2 ); if( in2D ) { R_Begin2D( multiSamples2D ); } else { R_PopRefInst(); } handle->new_frame = false; } } else { if( !handle->image ) { handle->image = R_LoadImage( handle->name, (uint8_t **)&handle->pic, handle->width, handle->height, IT_SPECIAL | IT_NO_DATA_SYNC, 1, IMAGE_TAG_GENERIC, samples ); } if( handle->new_frame ) { R_ReplaceImage( handle->image, (uint8_t **)&handle->pic, handle->width, handle->height, handle->image->flags, 1, samples ); handle->new_frame = false; } } ri.Mutex_Unlock( handle->lock ); }