2016-08-07 17:59:35 -07:00
// Copyright (c) 2012- PPSSPP Project.
2012-11-01 16:19:01 +01:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2013-12-29 23:44:35 +01:00
# include <set>
# include <algorithm>
2015-07-12 00:44:11 +02:00
# include "profiler/profiler.h"
2017-02-24 20:50:27 +01:00
# include "gfx/gl_common.h"
2017-03-03 14:15:27 +01:00
# include "gfx/gl_debug_log.h"
2012-11-01 16:19:01 +01:00
# include "gfx_es2/glsl_program.h"
2017-02-06 11:55:54 +01:00
# include "thin3d/thin3d.h"
2013-01-30 21:09:53 +01:00
2013-12-02 17:24:20 +01:00
# include "base/timeutil.h"
2017-12-07 17:02:00 +01:00
# include "file/vfs.h"
2012-11-01 16:19:01 +01:00
# include "math/lin/matrix4x4.h"
2015-04-08 00:16:22 +02:00
# include "Common/ColorConv.h"
2013-01-30 21:09:53 +01:00
# include "Core/Host.h"
# include "Core/MemMap.h"
# include "Core/Config.h"
# include "Core/System.h"
2013-09-11 22:21:15 +02:00
# include "Core/Reporting.h"
2013-01-30 21:09:53 +01:00
# include "GPU/ge_constants.h"
# include "GPU/GPUState.h"
2012-11-01 16:19:01 +01:00
2013-10-12 02:05:55 +02:00
# include "GPU/Common/PostShader.h"
2017-12-07 17:02:00 +01:00
# include "GPU/Common/ShaderTranslation.h"
2014-05-04 00:18:01 -07:00
# include "GPU/Common/TextureDecoder.h"
2015-01-23 10:40:49 +01:00
# include "GPU/Common/FramebufferCommon.h"
2014-06-13 08:35:12 -07:00
# include "GPU/Debugger/Stepping.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/FramebufferManagerGLES.h"
# include "GPU/GLES/TextureCacheGLES.h"
2016-04-10 10:27:28 +02:00
# include "GPU/GLES/DrawEngineGLES.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/ShaderManagerGLES.h"
2012-11-01 16:19:01 +01:00
2013-01-30 21:09:53 +01:00
static const char tex_fs [ ] =
2017-09-20 12:22:01 -07:00
" #if __VERSION__ >= 130 \n "
" #define varying in \n "
" #define texture2D texture \n "
" #define gl_FragColor fragColor0 \n "
" out vec4 fragColor0; \n "
" #endif \n "
2013-10-21 00:36:23 +02:00
# ifdef USING_GLES2
2012-11-01 16:19:01 +01:00
" precision mediump float; \n "
2013-10-21 00:36:23 +02:00
# endif
2012-11-01 16:19:01 +01:00
" uniform sampler2D sampler0; \n "
" varying vec2 v_texcoord0; \n "
" void main() { \n "
2014-06-17 23:10:38 -07:00
" gl_FragColor = texture2D(sampler0, v_texcoord0); \n "
2012-11-01 16:19:01 +01:00
" } \n " ;
2013-01-30 21:09:53 +01:00
static const char basic_vs [ ] =
2017-09-20 12:22:01 -07:00
" #if __VERSION__ >= 130 \n "
" #define attribute in \n "
" #define varying out \n "
" #endif \n "
2012-11-01 16:19:01 +01:00
" attribute vec4 a_position; \n "
" attribute vec2 a_texcoord0; \n "
" varying vec2 v_texcoord0; \n "
" void main() { \n "
2012-12-21 11:24:38 +01:00
" v_texcoord0 = a_texcoord0; \n "
2013-10-30 14:37:07 +01:00
" gl_Position = a_position; \n "
2012-11-01 16:19:01 +01:00
" } \n " ;
2017-12-07 14:56:19 +01:00
const int MAX_PBO = 2 ;
2014-09-13 16:37:59 -07:00
void ConvertFromRGBA8888 ( u8 * dst , const u8 * src , u32 dstStride , u32 srcStride , u32 width , u32 height , GEBufferFormat format ) ;
2013-06-28 14:48:36 +01:00
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : DisableState ( ) {
2017-03-19 12:14:43 -07:00
gstate_c . Dirty ( DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE ) ;
2013-08-15 03:32:43 +08:00
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : CompileDraw2DProgram ( ) {
2013-09-26 12:41:07 +02:00
if ( ! draw2dprogram_ ) {
2013-10-13 12:05:50 +02:00
std : : string errorString ;
2017-09-20 12:22:01 -07:00
static std : : string vs_code , fs_code ;
vs_code = ApplyGLSLPrelude ( basic_vs , GL_VERTEX_SHADER ) ;
fs_code = ApplyGLSLPrelude ( tex_fs , GL_FRAGMENT_SHADER ) ;
2017-12-12 14:07:52 +01:00
std : : vector < GLRShader * > shaders ;
2018-01-10 10:48:46 +01:00
shaders . push_back ( render_ - > CreateShader ( GL_VERTEX_SHADER , vs_code , " draw2d " ) ) ;
shaders . push_back ( render_ - > CreateShader ( GL_FRAGMENT_SHADER , fs_code , " draw2d " ) ) ;
2017-12-12 15:32:15 +01:00
2017-12-12 14:07:52 +01:00
std : : vector < GLRProgram : : UniformLocQuery > queries ;
queries . push_back ( { & u_draw2d_tex , " u_tex " } ) ;
std : : vector < GLRProgram : : Initializer > initializers ;
initializers . push_back ( { & u_draw2d_tex , 0 } ) ;
2017-12-15 11:05:43 +01:00
std : : vector < GLRProgram : : Semantic > semantics ;
semantics . push_back ( { 0 , " a_position " } ) ;
semantics . push_back ( { 1 , " a_texcoord0 " } ) ;
draw2dprogram_ = render_ - > CreateProgram ( shaders , semantics , queries , initializers , false ) ;
2017-12-12 15:32:15 +01:00
for ( auto shader : shaders )
render_ - > DeleteShader ( shader ) ;
2017-02-23 12:41:22 +01:00
CompilePostShader ( ) ;
}
}
2013-09-26 12:41:07 +02:00
2017-02-23 12:41:22 +01:00
void FramebufferManagerGLES : : CompilePostShader ( ) {
SetNumExtraFBOs ( 0 ) ;
const ShaderInfo * shaderInfo = 0 ;
if ( g_Config . sPostShaderName ! = " Off " ) {
2017-03-11 12:25:43 +01:00
ReloadAllPostShaderInfo ( ) ;
2017-02-23 12:41:22 +01:00
shaderInfo = GetPostShaderInfo ( g_Config . sPostShaderName ) ;
}
2013-10-12 02:05:55 +02:00
2017-02-23 12:41:22 +01:00
if ( shaderInfo ) {
std : : string errorString ;
postShaderAtOutputResolution_ = shaderInfo - > outputResolution ;
2017-12-07 17:02:00 +01:00
size_t sz ;
char * vs = ( char * ) VFSReadFile ( shaderInfo - > vertexShaderFile . c_str ( ) , & sz ) ;
if ( ! vs )
return ;
char * fs = ( char * ) VFSReadFile ( shaderInfo - > fragmentShaderFile . c_str ( ) , & sz ) ;
if ( ! fs ) {
free ( vs ) ;
return ;
}
std : : string vshader ;
std : : string fshader ;
bool translationFailed = false ;
if ( gl_extensions . IsCoreContext ) {
// Gonna have to upconvert the shaders.
std : : string errorMessage ;
if ( ! TranslateShader ( & vshader , GLSL_300 , nullptr , vs , GLSL_140 , Draw : : ShaderStage : : VERTEX , & errorMessage ) ) {
translationFailed = true ;
ELOG ( " Failed to translate post-vshader: %s " , errorMessage . c_str ( ) ) ;
}
if ( ! TranslateShader ( & fshader , GLSL_300 , nullptr , fs , GLSL_140 , Draw : : ShaderStage : : FRAGMENT , & errorMessage ) ) {
translationFailed = true ;
ELOG ( " Failed to translate post-fshader: %s " , errorMessage . c_str ( ) ) ;
}
} else {
vshader = vs ;
fshader = fs ;
}
if ( ! translationFailed ) {
2017-12-12 14:07:52 +01:00
SetNumExtraFBOs ( 1 ) ;
std : : vector < GLRShader * > shaders ;
2018-01-10 10:48:46 +01:00
shaders . push_back ( render_ - > CreateShader ( GL_VERTEX_SHADER , vshader , " postshader " ) ) ;
shaders . push_back ( render_ - > CreateShader ( GL_VERTEX_SHADER , fshader , " postshader " ) ) ;
2017-12-12 14:07:52 +01:00
std : : vector < GLRProgram : : UniformLocQuery > queries ;
queries . push_back ( { & u_postShaderTex , " tex " } ) ;
queries . push_back ( { & deltaLoc_ , " u_texelDelta " } ) ;
queries . push_back ( { & pixelDeltaLoc_ , " u_pixelDelta " } ) ;
queries . push_back ( { & timeLoc_ , " u_time " } ) ;
queries . push_back ( { & videoLoc_ , " u_video " } ) ;
std : : vector < GLRProgram : : Initializer > inits ;
inits . push_back ( { & u_postShaderTex , 0 , 0 } ) ;
postShaderProgram_ = render_ - > CreateProgram ( shaders , { } , queries , inits , false ) ;
render_ - > SetUniformI1 ( & u_postShaderTex , 0 ) ;
for ( auto iter : shaders ) {
render_ - > DeleteShader ( iter ) ;
}
2017-12-07 17:02:00 +01:00
} else {
ERROR_LOG ( FRAMEBUF , " Failed to translate post shader! " ) ;
}
free ( vs ) ;
free ( fs ) ;
2017-02-23 12:41:22 +01:00
if ( ! postShaderProgram_ ) {
// DO NOT turn this into a report, as it will pollute our logs with all kinds of
// user shader experiments.
2017-03-13 12:32:21 +01:00
ERROR_LOG ( FRAMEBUF , " Failed to build post-processing program from %s and %s! \n %s " , shaderInfo - > vertexShaderFile . c_str ( ) , shaderInfo - > fragmentShaderFile . c_str ( ) , errorString . c_str ( ) ) ;
2017-02-23 12:41:22 +01:00
// let's show the first line of the error string as an OSM.
std : : set < std : : string > blacklistedLines ;
// These aren't useful to show, skip to the first interesting line.
blacklistedLines . insert ( " Fragment shader failed to compile with the following errors: " ) ;
blacklistedLines . insert ( " Vertex shader failed to compile with the following errors: " ) ;
blacklistedLines . insert ( " Compile failed. " ) ;
blacklistedLines . insert ( " " ) ;
std : : string firstLine ;
size_t start = 0 ;
for ( size_t i = 0 ; i < errorString . size ( ) ; i + + ) {
if ( errorString [ i ] = = ' \n ' ) {
firstLine = errorString . substr ( start , i - start ) ;
if ( blacklistedLines . find ( firstLine ) = = blacklistedLines . end ( ) ) {
break ;
2013-10-13 12:05:50 +02:00
}
2017-02-23 12:41:22 +01:00
start = i + 1 ;
firstLine . clear ( ) ;
2013-10-13 12:05:50 +02:00
}
2017-02-23 12:41:22 +01:00
}
if ( ! firstLine . empty ( ) ) {
host - > NotifyUserMessage ( " Post-shader error: " + firstLine + " ... " , 10.0f , 0xFF3090FF ) ;
2013-10-09 16:08:36 +02:00
} else {
2017-02-23 12:41:22 +01:00
host - > NotifyUserMessage ( " Post-shader error, see log for details " , 10.0f , 0xFF3090FF ) ;
2013-10-09 16:08:36 +02:00
}
2013-10-12 02:05:55 +02:00
usePostShader_ = false ;
2017-02-23 12:41:22 +01:00
} else {
usePostShader_ = true ;
2013-09-26 12:41:07 +02:00
}
2017-02-23 12:41:22 +01:00
} else {
postShaderProgram_ = nullptr ;
usePostShader_ = false ;
2013-07-16 22:50:53 +02:00
}
2017-02-23 12:41:22 +01:00
glsl_unbind ( ) ;
2013-07-16 22:50:53 +02:00
}
2017-02-15 16:01:59 +01:00
void FramebufferManagerGLES : : Bind2DShader ( ) {
2017-12-12 14:07:52 +01:00
render_ - > BindProgram ( draw2dprogram_ ) ;
2017-02-15 16:01:59 +01:00
}
2017-02-15 12:18:08 +01:00
void FramebufferManagerGLES : : BindPostShader ( const PostShaderUniforms & uniforms ) {
2017-02-15 23:11:46 +01:00
// Make sure we've compiled the shader.
if ( ! postShaderProgram_ ) {
CompileDraw2DProgram ( ) ;
}
2017-12-12 14:07:52 +01:00
render_ - > BindProgram ( postShaderProgram_ ) ;
2015-10-31 16:02:25 +01:00
if ( deltaLoc_ ! = - 1 )
2017-12-12 14:07:52 +01:00
render_ - > SetUniformF ( & deltaLoc_ , 2 , uniforms . texelDelta ) ;
2015-10-31 16:02:25 +01:00
if ( pixelDeltaLoc_ ! = - 1 )
2017-12-12 14:07:52 +01:00
render_ - > SetUniformF ( & pixelDeltaLoc_ , 2 , uniforms . pixelDelta ) ;
2017-09-13 06:42:47 +02:00
if ( timeLoc_ ! = - 1 )
2017-12-12 14:07:52 +01:00
render_ - > SetUniformF ( & timeLoc_ , 4 , uniforms . time ) ;
2017-09-13 06:42:47 +02:00
if ( videoLoc_ ! = - 1 )
2017-12-12 14:07:52 +01:00
render_ - > SetUniformF ( & videoLoc_ , 1 , & uniforms . video ) ;
2015-10-31 16:02:25 +01:00
}
2017-12-12 14:07:52 +01:00
FramebufferManagerGLES : : FramebufferManagerGLES ( Draw : : DrawContext * draw , GLRenderManager * render ) :
2017-02-05 19:51:50 +01:00
FramebufferManagerCommon ( draw ) ,
2017-12-21 15:38:55 +01:00
render_ ( render )
2013-01-30 21:09:53 +01:00
{
2017-02-15 16:01:59 +01:00
needBackBufferYSwap_ = true ;
2017-05-23 11:12:10 +02:00
needGLESRebinds_ = true ;
2017-12-07 14:56:19 +01:00
CreateDeviceObjects ( ) ;
2017-11-19 12:25:57 +01:00
render_ = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
2014-06-15 15:19:49 -07:00
}
2013-01-14 19:26:10 +01:00
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : Init ( ) {
2014-09-13 16:47:23 -07:00
FramebufferManagerCommon : : Init ( ) ;
2015-10-14 20:07:06 +02:00
// Workaround for upscaling shaders where we force x1 resolution without saving it
2017-04-24 11:58:16 -07:00
Resized ( ) ;
2014-06-15 15:19:49 -07:00
CompileDraw2DProgram ( ) ;
2012-11-01 16:19:01 +01:00
}
2017-02-06 12:02:30 +01:00
void FramebufferManagerGLES : : SetTextureCache ( TextureCacheGLES * tc ) {
textureCacheGL_ = tc ;
textureCache_ = tc ;
}
2017-02-15 18:32:44 +01:00
void FramebufferManagerGLES : : SetShaderManager ( ShaderManagerGLES * sm ) {
shaderManagerGL_ = sm ;
shaderManager_ = sm ;
}
2017-10-18 12:26:02 +02:00
void FramebufferManagerGLES : : SetDrawEngine ( DrawEngineGLES * td ) {
drawEngineGL_ = td ;
drawEngine_ = td ;
}
2017-12-07 14:56:19 +01:00
void FramebufferManagerGLES : : CreateDeviceObjects ( ) {
CompileDraw2DProgram ( ) ;
2017-12-12 14:07:52 +01:00
std : : vector < GLRInputLayout : : Entry > entries ;
entries . push_back ( { 0 , 3 , GL_FLOAT , GL_FALSE , sizeof ( Simple2DVertex ) , offsetof ( Simple2DVertex , pos ) } ) ;
2017-12-14 14:53:27 +01:00
entries . push_back ( { 1 , 2 , GL_FLOAT , GL_FALSE , sizeof ( Simple2DVertex ) , offsetof ( Simple2DVertex , uv ) } ) ;
2017-12-12 14:07:52 +01:00
simple2DInputLayout_ = render_ - > CreateInputLayout ( entries ) ;
2017-12-07 14:56:19 +01:00
}
void FramebufferManagerGLES : : DestroyDeviceObjects ( ) {
2017-12-12 14:07:52 +01:00
if ( simple2DInputLayout_ ) {
render_ - > DeleteInputLayout ( simple2DInputLayout_ ) ;
simple2DInputLayout_ = nullptr ;
}
2017-12-07 14:56:19 +01:00
if ( draw2dprogram_ ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteProgram ( draw2dprogram_ ) ;
2017-12-07 14:56:19 +01:00
draw2dprogram_ = nullptr ;
}
if ( postShaderProgram_ ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteProgram ( postShaderProgram_ ) ;
2017-12-07 14:56:19 +01:00
postShaderProgram_ = nullptr ;
}
if ( drawPixelsTex_ ) {
2017-11-19 17:37:56 +01:00
render_ - > DeleteTexture ( drawPixelsTex_ ) ;
drawPixelsTex_ = 0 ;
}
2014-05-31 18:24:35 -07:00
if ( stencilUploadProgram_ ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteProgram ( stencilUploadProgram_ ) ;
2017-12-07 14:56:19 +01:00
stencilUploadProgram_ = nullptr ;
2014-05-31 18:24:35 -07:00
}
2017-12-07 14:56:19 +01:00
}
2013-06-28 14:48:36 +01:00
2017-12-07 14:56:19 +01:00
FramebufferManagerGLES : : ~ FramebufferManagerGLES ( ) {
DestroyDeviceObjects ( ) ;
2014-01-19 18:27:52 -08:00
2014-05-25 16:28:13 -07:00
delete [ ] convBuf_ ;
2012-11-01 16:19:01 +01:00
}
2017-03-22 20:56:26 -07:00
void FramebufferManagerGLES : : MakePixelTexture ( const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , int width , int height , float & u1 , float & v1 ) {
2017-03-22 20:57:45 -07:00
// Optimization: skip a copy if possible in a common case.
int texWidth = width ;
if ( srcPixelFormat = = GE_FORMAT_8888 & & width < srcStride ) {
// Don't up the upload requirements too much if subimages are unsupported.
if ( gstate_c . Supports ( GPU_SUPPORTS_UNPACK_SUBIMAGE ) | | width > = 480 ) {
texWidth = srcStride ;
u1 * = ( float ) width / texWidth ;
}
}
2017-12-15 11:05:43 +01:00
if ( drawPixelsTex_ ) {
2017-11-19 17:37:56 +01:00
render_ - > DeleteTexture ( drawPixelsTex_ ) ;
2013-06-05 23:03:23 +02:00
}
2017-12-15 11:05:43 +01:00
drawPixelsTex_ = render_ - > CreateTexture ( GL_TEXTURE_2D ) ;
drawPixelsTexW_ = texWidth ;
drawPixelsTexH_ = height ;
2013-06-05 23:03:23 +02:00
2017-12-15 11:05:43 +01:00
drawPixelsTexFormat_ = srcPixelFormat ;
2013-06-05 23:03:23 +02:00
2013-06-05 23:26:51 +02:00
// TODO: We can just change the texture format and flip some bits around instead of this.
2014-05-09 23:11:04 +02:00
// Could share code with the texture cache perhaps.
2017-11-19 18:22:46 +01:00
u32 neededSize = texWidth * height * 4 ;
u8 * convBuf = new u8 [ neededSize ] ;
for ( int y = 0 ; y < height ; y + + ) {
switch ( srcPixelFormat ) {
case GE_FORMAT_565 :
{
const u16 * src = ( const u16 * ) srcPixels + srcStride * y ;
u8 * dst = convBuf + 4 * texWidth * y ;
ConvertRGBA565ToRGBA8888 ( ( u32 * ) dst , src , width ) ;
}
break ;
2012-11-01 16:19:01 +01:00
2017-11-19 18:22:46 +01:00
case GE_FORMAT_5551 :
{
const u16 * src = ( const u16 * ) srcPixels + srcStride * y ;
u8 * dst = convBuf + 4 * texWidth * y ;
ConvertRGBA5551ToRGBA8888 ( ( u32 * ) dst , src , width ) ;
}
break ;
2012-11-01 16:19:01 +01:00
2017-11-19 18:22:46 +01:00
case GE_FORMAT_4444 :
{
const u16 * src = ( const u16 * ) srcPixels + srcStride * y ;
u8 * dst = convBuf + 4 * texWidth * y ;
ConvertRGBA4444ToRGBA8888 ( ( u32 * ) dst , src , width ) ;
}
break ;
2013-08-12 23:40:22 -07:00
2017-11-19 18:22:46 +01:00
case GE_FORMAT_8888 :
{
const u8 * src = srcPixels + srcStride * 4 * y ;
u8 * dst = convBuf + 4 * texWidth * y ;
memcpy ( dst , src , 4 * width ) ;
2012-11-01 16:19:01 +01:00
}
2017-11-19 18:22:46 +01:00
break ;
2017-03-22 20:57:45 -07:00
2017-11-19 18:22:46 +01:00
case GE_FORMAT_INVALID :
_dbg_assert_msg_ ( G3D , false , " Invalid pixelFormat passed to DrawPixels(). " ) ;
break ;
}
2017-03-22 20:57:45 -07:00
}
2017-12-15 11:05:43 +01:00
render_ - > TextureImage ( drawPixelsTex_ , 0 , texWidth , height , GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE , convBuf , false ) ;
render_ - > FinalizeTexture ( drawPixelsTex_ , 0 , false ) ;
2014-05-09 22:26:42 +02:00
}
2017-02-15 13:05:10 +01:00
void FramebufferManagerGLES : : SetViewport2D ( int x , int y , int w , int h ) {
2017-12-12 14:07:52 +01:00
render_ - > SetViewport ( { ( float ) x , ( float ) y , ( float ) w , ( float ) h , 0.0f , 1.0f } ) ;
2017-02-15 13:05:10 +01:00
}
2014-05-08 15:16:33 +02:00
// x, y, w, h are relative coordinates against destW/destH, which is not very intuitive.
2017-02-15 12:32:48 +01:00
// TODO: This could totally use fbo_blit in many cases.
2017-05-31 23:24:56 -07:00
void FramebufferManagerGLES : : DrawActiveTexture ( float x , float y , float w , float h , float destW , float destH , float u0 , float v0 , float u1 , float v1 , int uvRotation , int flags ) {
2015-05-12 21:01:15 +02:00
float texCoords [ 8 ] = {
u0 , v0 ,
u1 , v0 ,
u1 , v1 ,
2015-11-01 22:23:37 +01:00
u0 , v1 ,
2015-05-12 21:01:15 +02:00
} ;
2017-12-12 14:07:52 +01:00
static const GLushort indices [ 4 ] = { 0 , 1 , 3 , 2 } ;
2013-12-06 13:01:34 +01:00
2015-05-12 21:01:15 +02:00
if ( uvRotation ! = ROTATION_LOCKED_HORIZONTAL ) {
float temp [ 8 ] ;
int rotation = 0 ;
2016-01-17 11:01:56 +01:00
// Vertical and Vertical180 needed swapping after we changed the coordinate system.
2015-05-12 21:01:15 +02:00
switch ( uvRotation ) {
case ROTATION_LOCKED_HORIZONTAL180 : rotation = 4 ; break ;
2016-01-17 11:01:56 +01:00
case ROTATION_LOCKED_VERTICAL : rotation = 6 ; break ;
case ROTATION_LOCKED_VERTICAL180 : rotation = 2 ; break ;
2015-05-12 21:01:15 +02:00
}
for ( int i = 0 ; i < 8 ; i + + ) {
temp [ i ] = texCoords [ ( i + rotation ) & 7 ] ;
}
memcpy ( texCoords , temp , sizeof ( temp ) ) ;
}
2013-10-30 14:37:07 +01:00
float pos [ 12 ] = {
x , y , 0 ,
2017-12-12 14:07:52 +01:00
x + w , y , 0 ,
x + w , y + h , 0 ,
x , y + h , 0
2013-10-30 14:37:07 +01:00
} ;
2014-05-08 15:28:25 +02:00
float invDestW = 1.0f / ( destW * 0.5f ) ;
float invDestH = 1.0f / ( destH * 0.5f ) ;
2013-10-30 14:37:07 +01:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-05-08 15:28:25 +02:00
pos [ i * 3 ] = pos [ i * 3 ] * invDestW - 1.0f ;
2015-11-01 15:34:53 +01:00
pos [ i * 3 + 1 ] = pos [ i * 3 + 1 ] * invDestH - 1.0f ;
2013-10-30 14:37:07 +01:00
}
2015-10-14 18:32:13 +02:00
// Upscaling postshaders doesn't look well with linear
2017-05-31 23:24:56 -07:00
if ( flags & DRAWTEX_LINEAR ) {
2017-12-12 14:07:52 +01:00
render_ - > SetTextureSampler ( GL_CLAMP_TO_EDGE , GL_CLAMP_TO_EDGE , GL_LINEAR , GL_LINEAR , 0.0f ) ;
2017-02-06 16:06:03 +01:00
} else {
2017-12-12 14:07:52 +01:00
render_ - > SetTextureSampler ( GL_CLAMP_TO_EDGE , GL_CLAMP_TO_EDGE , GL_NEAREST , GL_NEAREST , 0.0f ) ;
2013-12-02 17:24:20 +01:00
}
2015-10-31 16:02:25 +01:00
2017-12-12 14:07:52 +01:00
Simple2DVertex verts [ 4 ] ;
memcpy ( verts [ 0 ] . pos , & pos [ 0 ] , 12 ) ;
memcpy ( verts [ 1 ] . pos , & pos [ 3 ] , 12 ) ;
memcpy ( verts [ 3 ] . pos , & pos [ 6 ] , 12 ) ;
memcpy ( verts [ 2 ] . pos , & pos [ 9 ] , 12 ) ;
memcpy ( verts [ 0 ] . uv , & texCoords [ 0 ] , 8 ) ;
memcpy ( verts [ 1 ] . uv , & texCoords [ 2 ] , 8 ) ;
memcpy ( verts [ 3 ] . uv , & texCoords [ 4 ] , 8 ) ;
memcpy ( verts [ 2 ] . uv , & texCoords [ 6 ] , 8 ) ;
uint32_t bindOffset ;
GLRBuffer * buffer ;
void * dest = drawEngineGL_ - > GetPushVertexBuffer ( ) - > Push ( sizeof ( verts ) , & bindOffset , & buffer ) ;
memcpy ( dest , verts , sizeof ( verts ) ) ;
2017-12-19 12:25:13 +01:00
render_ - > BindVertexBuffer ( simple2DInputLayout_ , buffer , bindOffset ) ;
2017-12-12 14:07:52 +01:00
render_ - > Draw ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
2014-03-30 00:11:01 +01:00
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : ReformatFramebufferFrom ( VirtualFramebuffer * vfb , GEBufferFormat old ) {
2014-09-11 23:30:42 -07:00
if ( ! useBufferedRendering_ | | ! vfb - > fbo ) {
2014-09-07 08:47:04 -07:00
return ;
}
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if ( old = = GE_FORMAT_565 ) {
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( vfb - > fbo , { Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR } ) ;
2017-05-16 16:00:34 +02:00
} else {
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( vfb - > fbo , { Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP } ) ;
2014-09-07 08:47:04 -07:00
}
RebindFramebuffer ( ) ;
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : BlitFramebufferDepth ( VirtualFramebuffer * src , VirtualFramebuffer * dst ) {
2016-02-10 21:02:19 -08:00
if ( g_Config . bDisableSlowFramebufEffects ) {
return ;
}
2016-01-20 21:35:19 -08:00
bool matchingDepthBuffer = src - > z_address = = dst - > z_address & & src - > z_stride ! = 0 & & dst - > z_stride ! = 0 ;
bool matchingSize = src - > width = = dst - > width & & src - > height = = dst - > height ;
2017-02-21 10:44:52 +01:00
2017-06-01 20:57:08 -07:00
// Note: we don't use CopyFramebufferImage here, because it would copy depth AND stencil. See #9740.
if ( matchingDepthBuffer & & matchingSize ) {
2016-01-20 21:35:19 -08:00
int w = std : : min ( src - > renderWidth , dst - > renderWidth ) ;
int h = std : : min ( src - > renderHeight , dst - > renderHeight ) ;
2014-06-11 00:40:47 -07:00
2015-09-05 22:40:45 +02:00
if ( gstate_c . Supports ( GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT ) ) {
2015-07-26 22:54:18 +02:00
// Let's only do this if not clearing depth.
2017-02-06 11:26:24 +01:00
draw_ - > BlitFramebuffer ( src - > fbo , 0 , 0 , w , h , dst - > fbo , 0 , 0 , w , h , Draw : : FB_DEPTH_BIT , Draw : : FB_BLIT_NEAREST ) ;
2017-12-24 11:52:15 -08:00
dst - > last_frame_depth_updated = gpuStats . numFlips ;
2014-01-20 22:02:20 +08:00
}
}
2014-01-19 17:28:11 -08:00
}
2017-02-17 14:30:42 +01:00
void FramebufferManagerGLES : : BindFramebufferAsColorTexture ( int stage , VirtualFramebuffer * framebuffer , int flags ) {
2014-01-19 17:28:11 -08:00
if ( ! framebuffer - > fbo | | ! useBufferedRendering_ ) {
2017-12-12 14:07:52 +01:00
render_ - > BindTexture ( 0 , nullptr ) ;
2014-01-19 17:28:11 -08:00
gstate_c . skipDrawReason | = SKIPDRAW_BAD_FB_TEXTURE ;
return ;
}
2014-05-23 08:48:29 -07:00
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
2015-09-13 11:14:51 -07:00
bool skipCopy = ( flags & BINDFBCOLOR_MAY_COPY ) = = 0 ;
2014-07-08 23:32:41 -07:00
if ( GPUStepping : : IsStepping ( ) | | g_Config . bDisableSlowFramebufEffects ) {
2014-06-13 08:35:12 -07:00
skipCopy = true ;
}
2017-02-17 12:13:53 +01:00
if ( ! skipCopy & & currentRenderVfb_ & & framebuffer - > fb_address = = gstate . getFrameBufRawAddress ( ) ) {
2014-05-30 08:53:22 -07:00
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
2017-02-04 18:46:12 +01:00
Draw : : Framebuffer * renderCopy = GetTempFBO ( framebuffer - > renderWidth , framebuffer - > renderHeight , ( Draw : : FBColorDepth ) framebuffer - > colorDepth ) ;
2014-05-31 22:41:41 -07:00
if ( renderCopy ) {
VirtualFramebuffer copyInfo = * framebuffer ;
copyInfo . fbo = renderCopy ;
2017-04-06 18:49:48 -07:00
CopyFramebufferForColorTexture ( & copyInfo , framebuffer , flags ) ;
2017-02-15 23:56:38 +01:00
draw_ - > BindFramebufferAsTexture ( renderCopy , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-05-31 22:41:41 -07:00
} else {
2017-02-15 23:56:38 +01:00
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-05-30 08:53:22 -07:00
}
2014-01-19 17:28:11 -08:00
} else {
2017-02-15 23:56:38 +01:00
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-09-21 12:11:17 -07:00
}
2014-01-20 22:02:20 +08:00
}
2017-01-21 22:16:30 +01:00
bool FramebufferManagerGLES : : CreateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
2016-01-04 20:51:43 -08:00
// When updating VRAM, it need to be exact format.
if ( ! gstate_c . Supports ( GPU_PREFER_CPU_DOWNLOAD ) ) {
switch ( nvfb - > format ) {
case GE_FORMAT_4444 :
2017-02-04 18:46:12 +01:00
nvfb - > colorDepth = Draw : : FBO_4444 ;
2016-01-04 20:51:43 -08:00
break ;
case GE_FORMAT_5551 :
2017-02-04 18:46:12 +01:00
nvfb - > colorDepth = Draw : : FBO_5551 ;
2016-01-04 20:51:43 -08:00
break ;
case GE_FORMAT_565 :
2017-02-04 18:46:12 +01:00
nvfb - > colorDepth = Draw : : FBO_565 ;
2016-01-04 20:51:43 -08:00
break ;
case GE_FORMAT_8888 :
default :
2017-02-04 18:46:12 +01:00
nvfb - > colorDepth = Draw : : FBO_8888 ;
2016-01-04 20:51:43 -08:00
break ;
}
}
2017-02-06 11:26:24 +01:00
nvfb - > fbo = draw_ - > CreateFramebuffer ( { nvfb - > width , nvfb - > height , 1 , 1 , false , ( Draw : : FBColorDepth ) nvfb - > colorDepth } ) ;
2017-02-04 17:44:31 +01:00
if ( ! nvfb - > fbo ) {
2017-03-13 12:32:21 +01:00
ERROR_LOG ( FRAMEBUF , " Error creating GL FBO! %i x %i " , nvfb - > renderWidth , nvfb - > renderHeight ) ;
2016-01-04 20:51:43 -08:00
return false ;
}
return true ;
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : UpdateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
2016-01-04 20:57:54 -08:00
_assert_msg_ ( G3D , nvfb - > fbo , " Expecting a valid nvfb in UpdateDownloadTempBuffer " ) ;
// Discard the previous contents of this buffer where possible.
if ( gl_extensions . GLES3 & & glInvalidateFramebuffer ! = nullptr ) {
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( nvfb - > fbo , { Draw : : RPAction : : DONT_CARE , Draw : : RPAction : : DONT_CARE , Draw : : RPAction : : DONT_CARE } ) ;
2016-01-04 20:57:54 -08:00
} else if ( gl_extensions . IsGLES ) {
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( nvfb - > fbo , { Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR } ) ;
2016-01-04 20:51:43 -08:00
}
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : BlitFramebuffer ( VirtualFramebuffer * dst , int dstX , int dstY , VirtualFramebuffer * src , int srcX , int srcY , int w , int h , int bpp ) {
2014-07-09 23:40:29 -07:00
if ( ! dst - > fbo | | ! src - > fbo | | ! useBufferedRendering_ ) {
// This can happen if they recently switched from non-buffered.
2017-05-16 16:00:34 +02:00
if ( useBufferedRendering_ )
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr , { Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP } ) ;
2014-05-08 15:16:33 +02:00
return ;
}
2015-09-05 16:28:59 -07:00
bool useBlit = gstate_c . Supports ( GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT ) ;
bool useNV = useBlit & & ! gstate_c . Supports ( GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT ) ;
2013-10-09 11:01:52 +02:00
2014-06-05 00:14:31 -07:00
float srcXFactor = useBlit ? ( float ) src - > renderWidth / ( float ) src - > bufferWidth : 1.0f ;
float srcYFactor = useBlit ? ( float ) src - > renderHeight / ( float ) src - > bufferHeight : 1.0f ;
const int srcBpp = src - > format = = GE_FORMAT_8888 ? 4 : 2 ;
if ( srcBpp ! = bpp & & bpp ! = 0 ) {
srcXFactor = ( srcXFactor * bpp ) / srcBpp ;
}
int srcX1 = srcX * srcXFactor ;
int srcX2 = ( srcX + w ) * srcXFactor ;
2015-11-01 22:23:37 +01:00
int srcY1 = srcY * srcYFactor ;
int srcY2 = ( srcY + h ) * srcYFactor ;
2014-06-05 00:14:31 -07:00
float dstXFactor = useBlit ? ( float ) dst - > renderWidth / ( float ) dst - > bufferWidth : 1.0f ;
float dstYFactor = useBlit ? ( float ) dst - > renderHeight / ( float ) dst - > bufferHeight : 1.0f ;
const int dstBpp = dst - > format = = GE_FORMAT_8888 ? 4 : 2 ;
if ( dstBpp ! = bpp & & bpp ! = 0 ) {
dstXFactor = ( dstXFactor * bpp ) / dstBpp ;
}
int dstX1 = dstX * dstXFactor ;
int dstX2 = ( dstX + w ) * dstXFactor ;
2015-11-01 00:13:37 +01:00
int dstY1 = dstY * dstYFactor ;
int dstY2 = ( dstY + h ) * dstYFactor ;
2014-05-25 15:13:19 -07:00
2015-12-30 10:27:18 -08:00
if ( src = = dst & & srcX = = dstX & & srcY = = dstY ) {
// Let's just skip a copy where the destination is equal to the source.
WARN_LOG_REPORT_ONCE ( blitSame , G3D , " Skipped blit with equal dst and src " ) ;
return ;
}
2015-12-06 10:39:21 -08:00
if ( gstate_c . Supports ( GPU_SUPPORTS_ANY_COPY_IMAGE ) ) {
2015-12-28 22:23:07 -08:00
// glBlitFramebuffer can clip, but glCopyImageSubData is more restricted.
// In case the src goes outside, we just skip the optimization in that case.
const bool sameSize = dstX2 - dstX1 = = srcX2 - srcX1 & & dstY2 - dstY1 = = srcY2 - srcY1 ;
2015-12-30 10:27:18 -08:00
const bool sameDepth = dst - > colorDepth = = src - > colorDepth ;
2015-12-28 22:23:07 -08:00
const bool srcInsideBounds = srcX2 < = src - > renderWidth & & srcY2 < = src - > renderHeight ;
const bool dstInsideBounds = dstX2 < = dst - > renderWidth & & dstY2 < = dst - > renderHeight ;
2015-12-30 10:27:18 -08:00
const bool xOverlap = src = = dst & & srcX2 > dstX1 & & srcX1 < dstX2 ;
const bool yOverlap = src = = dst & & srcY2 > dstY1 & & srcY1 < dstY2 ;
if ( sameSize & & sameDepth & & srcInsideBounds & & dstInsideBounds & & ! ( xOverlap & & yOverlap ) ) {
2017-02-12 11:20:55 +01:00
draw_ - > CopyFramebufferImage ( src - > fbo , 0 , srcX1 , srcY1 , 0 , dst - > fbo , 0 , dstX1 , dstY1 , 0 , dstX2 - dstX1 , dstY2 - dstY1 , 1 , Draw : : FB_COLOR_BIT ) ;
2015-12-06 10:39:21 -08:00
return ;
}
}
2014-06-05 00:14:31 -07:00
if ( useBlit ) {
2017-02-06 11:26:24 +01:00
draw_ - > BlitFramebuffer ( src - > fbo , srcX1 , srcY1 , srcX2 , srcY2 , dst - > fbo , dstX1 , dstY1 , dstX2 , dstY2 , Draw : : FB_COLOR_BIT , Draw : : FB_BLIT_NEAREST ) ;
2014-05-09 22:01:30 +08:00
} else {
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( dst - > fbo , { Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP } ) ;
2017-02-06 11:26:24 +01:00
draw_ - > BindFramebufferAsTexture ( src - > fbo , 0 , Draw : : FB_COLOR_BIT , 0 ) ;
2014-05-09 22:01:30 +08:00
// Make sure our 2D drawing program is ready. Compiles only if not already compiled.
CompileDraw2DProgram ( ) ;
2017-12-12 14:07:52 +01:00
render_ - > SetViewport ( { 0 , 0 , ( float ) dst - > renderWidth , ( float ) dst - > renderHeight , 0 , 1.0f } ) ;
render_ - > SetStencilDisabled ( ) ;
render_ - > SetDepth ( false , false , GL_ALWAYS ) ;
render_ - > SetNoBlendAndMask ( 0xF ) ;
2014-05-09 22:01:30 +08:00
// The first four coordinates are relative to the 6th and 7th arguments of DrawActiveTexture.
// Should maybe revamp that interface.
2014-06-01 21:20:04 -07:00
float srcW = src - > bufferWidth ;
float srcH = src - > bufferHeight ;
2017-12-12 14:07:52 +01:00
render_ - > BindProgram ( draw2dprogram_ ) ;
2017-05-31 23:24:56 -07:00
DrawActiveTexture ( dstX1 , dstY1 , w * dstXFactor , h , dst - > bufferWidth , dst - > bufferHeight , srcX1 / srcW , srcY1 / srcH , srcX2 / srcW , srcY2 / srcH , ROTATION_LOCKED_HORIZONTAL , DRAWTEX_NEAREST ) ;
2017-02-06 12:02:30 +01:00
textureCacheGL_ - > ForgetLastTexture ( ) ;
2014-05-09 22:01:30 +08:00
}
2013-10-09 11:01:52 +02:00
2017-12-12 14:07:52 +01:00
gstate_c . Dirty ( DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE ) ;
2013-06-28 14:48:36 +01:00
}
2013-07-06 11:09:08 +02:00
// TODO: SSE/NEON
2013-10-23 14:46:04 +02:00
// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :)
2014-09-13 16:37:59 -07:00
void ConvertFromRGBA8888 ( u8 * dst , const u8 * src , u32 dstStride , u32 srcStride , u32 width , u32 height , GEBufferFormat format ) {
2014-06-15 19:33:32 -07:00
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
const u32 * src32 = ( const u32 * ) src ;
2015-01-22 19:53:32 +01:00
2013-10-09 11:01:52 +02:00
if ( format = = GE_FORMAT_8888 ) {
2014-06-15 19:33:32 -07:00
u32 * dst32 = ( u32 * ) dst ;
2013-10-09 11:01:52 +02:00
if ( src = = dst ) {
2013-07-02 14:08:59 +01:00
return ;
2014-05-08 10:46:19 +02:00
} else {
// Here let's assume they don't intersect
2014-06-15 19:33:32 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
memcpy ( dst32 , src32 , width * 4 ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst32 + = dstStride ;
2014-06-15 19:33:32 -07:00
}
2013-07-02 14:08:59 +01:00
}
2014-05-08 10:46:19 +02:00
} else {
// But here it shouldn't matter if they do intersect
2013-07-05 02:31:31 +01:00
u16 * dst16 = ( u16 * ) dst ;
switch ( format ) {
case GE_FORMAT_565 : // BGR 565
2017-03-26 11:39:25 +02:00
{
2014-06-15 19:33:32 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
2015-04-08 19:59:12 +02:00
ConvertRGBA8888ToRGB565 ( dst16 , src32 , width ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst16 + = dstStride ;
2014-05-04 00:18:01 -07:00
}
2013-07-05 02:31:31 +01:00
}
break ;
case GE_FORMAT_5551 : // ABGR 1555
2017-03-26 11:39:25 +02:00
{
2014-06-15 19:33:32 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
ConvertRGBA8888ToRGBA5551 ( dst16 , src32 , width ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst16 + = dstStride ;
2014-06-15 19:33:32 -07:00
}
2013-07-05 02:31:31 +01:00
}
break ;
case GE_FORMAT_4444 : // ABGR 4444
2017-03-26 11:39:25 +02:00
{
2014-06-15 19:33:32 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
2015-04-08 19:59:12 +02:00
ConvertRGBA8888ToRGBA4444 ( dst16 , src32 , width ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst16 + = dstStride ;
2014-05-04 00:18:01 -07:00
}
2013-07-05 02:31:31 +01:00
}
break ;
2013-07-29 23:05:59 -07:00
case GE_FORMAT_8888 :
2014-05-04 00:18:01 -07:00
case GE_FORMAT_INVALID :
2013-07-29 23:05:59 -07:00
// Not possible.
break ;
2013-06-25 13:50:35 +01:00
}
2013-06-28 14:48:36 +01:00
}
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : PackDepthbuffer ( VirtualFramebuffer * vfb , int x , int y , int w , int h ) {
2017-10-10 14:46:47 +02:00
if ( ! vfb - > fbo ) {
2016-01-18 12:57:37 -08:00
ERROR_LOG_REPORT_ONCE ( vfbfbozero , SCEGE , " PackDepthbuffer: vfb->fbo == 0 " ) ;
return ;
}
// Pixel size always 4 here because we always request float
const u32 bufSize = vfb - > z_stride * ( h - y ) * 4 ;
const u32 z_address = ( 0x04000000 ) | vfb - > z_address ;
const int packWidth = std : : min ( vfb - > z_stride , std : : min ( x + w , ( int ) vfb - > width ) ) ;
if ( ! convBuf_ | | convBufSize_ < bufSize ) {
delete [ ] convBuf_ ;
convBuf_ = new u8 [ bufSize ] ;
convBufSize_ = bufSize ;
}
2017-03-13 12:32:21 +01:00
DEBUG_LOG ( FRAMEBUF , " Reading depthbuffer to mem at %08x for vfb=%08x " , z_address , vfb - > fb_address ) ;
2016-01-18 12:57:37 -08:00
2017-12-21 11:41:53 -08:00
draw_ - > CopyFramebufferToMemorySync ( vfb - > fbo , Draw : : FB_DEPTH_BIT , 0 , y , packWidth , h , Draw : : DataFormat : : D32F , convBuf_ , vfb - > z_stride ) ;
2016-01-18 12:57:37 -08:00
2017-12-21 11:41:53 -08:00
int dstByteOffset = y * vfb - > z_stride * sizeof ( u16 ) ;
2016-01-18 12:57:37 -08:00
u16 * depth = ( u16 * ) Memory : : GetPointer ( z_address + dstByteOffset ) ;
GLfloat * packed = ( GLfloat * ) convBuf_ ;
int totalPixels = h = = 1 ? packWidth : vfb - > z_stride * h ;
2017-12-21 11:41:53 -08:00
for ( int yp = 0 ; yp < h ; + + yp ) {
int row_offset = vfb - > z_stride * yp ;
for ( int xp = 0 ; xp < packWidth ; + + xp ) {
const int i = row_offset + xp ;
float scaled = FromScaledDepth ( packed [ i ] ) ;
if ( scaled < = 0.0f ) {
depth [ i ] = 0 ;
} else if ( scaled > = 65535.0f ) {
depth [ i ] = 65535 ;
} else {
depth [ i ] = ( int ) scaled ;
}
2016-01-18 12:57:37 -08:00
}
}
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : EndFrame ( ) {
2013-01-30 21:09:53 +01:00
}
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : DeviceLost ( ) {
2017-04-13 23:07:21 -07:00
DestroyAllFBOs ( ) ;
2017-12-07 14:56:19 +01:00
DestroyDeviceObjects ( ) ;
}
void FramebufferManagerGLES : : DeviceRestore ( Draw : : DrawContext * draw ) {
draw_ = draw ;
CreateDeviceObjects ( ) ;
2013-06-11 11:28:41 +02:00
}
2017-04-13 23:07:21 -07:00
void FramebufferManagerGLES : : DestroyAllFBOs ( ) {
2013-06-09 02:11:16 -07:00
currentRenderVfb_ = 0 ;
2013-06-11 04:07:48 +08:00
displayFramebuf_ = 0 ;
prevDisplayFramebuf_ = 0 ;
prevPrevDisplayFramebuf_ = 0 ;
2013-06-09 02:11:16 -07:00
2013-06-23 08:51:35 -07:00
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = vfbs_ [ i ] ;
2017-03-13 12:32:21 +01:00
INFO_LOG ( FRAMEBUF , " Destroying FBO for %08x : %i x %i x %i " , vfb - > fb_address , vfb - > width , vfb - > height , vfb - > format ) ;
2013-06-23 08:16:22 -07:00
DestroyFramebuf ( vfb ) ;
2013-01-30 21:09:53 +01:00
}
vfbs_ . clear ( ) ;
2014-07-04 23:27:12 -07:00
for ( size_t i = 0 ; i < bvfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = bvfbs_ [ i ] ;
DestroyFramebuf ( vfb ) ;
}
bvfbs_ . clear ( ) ;
for ( auto it = tempFBOs_ . begin ( ) , end = tempFBOs_ . end ( ) ; it ! = end ; + + it ) {
2017-11-05 12:45:02 -08:00
it - > second . fbo - > Release ( ) ;
2014-07-04 23:27:12 -07:00
}
tempFBOs_ . clear ( ) ;
2014-08-03 18:45:36 -07:00
2017-12-01 12:15:55 +01:00
SetNumExtraFBOs ( 0 ) ;
2014-08-03 18:45:36 -07:00
DisableState ( ) ;
2013-01-30 21:09:53 +01:00
}
2013-01-31 19:14:57 +08:00
2017-01-21 22:16:30 +01:00
void FramebufferManagerGLES : : Resized ( ) {
2017-04-24 11:58:16 -07:00
FramebufferManagerCommon : : Resized ( ) ;
2017-12-12 15:04:46 +01:00
render_ - > Resize ( PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight ) ;
2017-04-24 11:58:16 -07:00
if ( UpdateSize ( ) ) {
DestroyAllFBOs ( ) ;
}
2017-12-14 14:53:27 +01:00
// render_->SetLineWidth(renderWidth_ / 480.0f);
2013-01-31 19:14:57 +08:00
}
2013-09-22 19:03:31 -07:00
2017-01-21 22:16:30 +01:00
bool FramebufferManagerGLES : : GetOutputFramebuffer ( GPUDebugBuffer & buffer ) {
2017-10-16 16:27:16 +02:00
int w , h ;
draw_ - > GetFramebufferDimensions ( nullptr , & w , & h ) ;
buffer . Allocate ( w , h , GPU_DBG_FORMAT_888_RGB , true ) ;
draw_ - > CopyFramebufferToMemorySync ( nullptr , Draw : : FB_COLOR_BIT , 0 , 0 , w , h , Draw : : DataFormat : : R8G8B8_UNORM , buffer . GetData ( ) , w ) ;
2014-12-20 08:31:56 -08:00
return true ;
2017-12-21 11:41:53 -08:00
}