2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// 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:58:25 +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-02-10 13:19:01 -08:00
# include <algorithm>
2013-12-29 15:55:09 -08:00
# include <cstring>
2012-11-01 16:19:01 +01:00
2015-09-06 13:45:17 +02:00
# include "ext/xxhash.h"
2022-01-30 15:49:02 -08:00
# include "Common/Common.h"
2021-05-01 07:15:04 -07:00
# include "Common/Data/Convert/ColorConv.h"
2020-10-01 13:05:04 +02:00
# include "Common/Data/Text/I18n.h"
2020-10-04 00:25:21 +02:00
# include "Common/Math/math_util.h"
2020-10-04 10:04:01 +02:00
# include "Common/Profiler/Profiler.h"
2023-06-30 17:15:49 +02:00
# include "Common/System/OSD.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/OpenGL/GLRenderManager.h"
2021-10-17 08:54:45 -07:00
# include "Common/TimeUtil.h"
2015-05-13 22:28:02 +02:00
2015-12-30 13:29:29 -08:00
# include "Core/Config.h"
2013-02-21 21:37:19 +01:00
# include "Core/MemMap.h"
# include "GPU/ge_constants.h"
# include "GPU/GPUState.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/TextureCacheGLES.h"
# include "GPU/GLES/FramebufferManagerGLES.h"
2020-10-31 18:56:44 +01:00
# include "GPU/Common/FragmentShaderGenerator.h"
2022-08-22 12:20:21 +02:00
# include "GPU/Common/TextureShaderCommon.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/ShaderManagerGLES.h"
2016-04-10 10:27:28 +02:00
# include "GPU/GLES/DrawEngineGLES.h"
2013-09-15 21:27:13 -07:00
# include "GPU/Common/TextureDecoder.h"
2012-11-01 16:19:01 +01:00
2013-05-05 19:58:59 -07:00
# ifdef _M_SSE
2017-03-12 17:16:38 +01:00
# include <emmintrin.h>
2013-05-05 19:58:59 -07:00
# endif
2022-08-23 11:11:04 +02:00
TextureCacheGLES : : TextureCacheGLES ( Draw : : DrawContext * draw , Draw2D * draw2D )
: TextureCacheCommon ( draw , draw2D ) {
2017-11-19 17:37:56 +01:00
render_ = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
2014-04-01 14:14:56 +02:00
2015-03-15 19:10:33 -07:00
nextTexture_ = nullptr ;
2012-11-28 16:12:29 +01:00
}
2017-01-21 22:16:30 +01:00
TextureCacheGLES : : ~ TextureCacheGLES ( ) {
2015-01-24 20:36:01 -08:00
Clear ( true ) ;
2012-11-28 16:12:29 +01:00
}
2017-02-08 15:58:46 +01:00
void TextureCacheGLES : : SetFramebufferManager ( FramebufferManagerGLES * fbManager ) {
framebufferManagerGL_ = fbManager ;
framebufferManager_ = fbManager ;
}
2017-02-23 17:31:24 +01:00
void TextureCacheGLES : : ReleaseTexture ( TexCacheEntry * entry , bool delete_them ) {
2017-02-23 22:41:13 +01:00
if ( delete_them ) {
2017-11-19 17:37:56 +01:00
if ( entry - > textureName ) {
render_ - > DeleteTexture ( entry - > textureName ) ;
2017-02-23 22:41:13 +01:00
}
}
2017-11-19 17:37:56 +01:00
entry - > textureName = nullptr ;
2017-02-19 22:31:07 +01:00
}
2017-01-21 22:16:30 +01:00
void TextureCacheGLES : : Clear ( bool delete_them ) {
2017-02-19 22:31:07 +01:00
TextureCacheCommon : : Clear ( delete_them ) ;
2012-11-01 16:19:01 +01:00
}
2019-10-24 22:40:26 +02:00
Draw : : DataFormat getClutDestFormat ( GEPaletteFormat format ) {
2013-01-06 12:11:47 +01:00
switch ( format ) {
2012-11-08 23:26:30 +01:00
case GE_CMODE_16BIT_ABGR4444 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R4G4B4A4_UNORM_PACK16 ;
2012-11-08 23:26:30 +01:00
case GE_CMODE_16BIT_ABGR5551 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R5G5B5A1_UNORM_PACK16 ;
2012-11-08 23:26:30 +01:00
case GE_CMODE_16BIT_BGR5650 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R5G6B5_UNORM_PACK16 ;
2012-11-08 23:26:30 +01:00
case GE_CMODE_32BIT_ABGR8888 :
2019-10-24 22:40:26 +02:00
return Draw : : DataFormat : : R8G8B8A8_UNORM ;
2012-11-08 23:26:30 +01:00
}
2022-08-05 10:00:27 +02:00
return Draw : : DataFormat : : UNDEFINED ;
2012-11-08 23:26:30 +01:00
}
2013-02-08 00:04:34 +01:00
static const GLuint MinFiltGL [ 8 ] = {
2013-01-06 17:44:14 +01:00
GL_NEAREST ,
GL_LINEAR ,
GL_NEAREST ,
GL_LINEAR ,
GL_NEAREST_MIPMAP_NEAREST ,
GL_LINEAR_MIPMAP_NEAREST ,
GL_NEAREST_MIPMAP_LINEAR ,
GL_LINEAR_MIPMAP_LINEAR ,
} ;
2013-02-08 00:04:34 +01:00
static const GLuint MagFiltGL [ 2 ] = {
2013-01-06 17:44:14 +01:00
GL_NEAREST ,
GL_LINEAR
} ;
2020-09-13 22:48:44 +02:00
void TextureCacheGLES : : ApplySamplingParams ( const SamplerCacheKey & key ) {
2022-10-17 08:30:27 +02:00
if ( gstate_c . Use ( GPU_USE_TEXTURE_LOD_CONTROL ) ) {
2020-09-13 22:48:44 +02:00
float minLod = ( float ) key . minLevel / 256.0f ;
float maxLod = ( float ) key . maxLevel / 256.0f ;
float lodBias = ( float ) key . lodBias / 256.0f ;
2018-02-07 19:49:31 +01:00
render_ - > SetTextureLod ( 0 , minLod , maxLod , lodBias ) ;
2014-06-15 13:34:58 -07:00
}
2013-06-17 20:45:08 +02:00
2017-12-27 14:33:18 +01:00
float aniso = 0.0f ;
2020-09-17 20:47:22 +02:00
int minKey = ( ( int ) key . mipEnable < < 2 ) | ( ( int ) key . mipFilt < < 1 ) | ( ( int ) key . minFilt ) ;
2020-09-13 22:48:44 +02:00
render_ - > SetTextureSampler ( 0 ,
key . sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT , key . tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT ,
2020-09-17 20:47:22 +02:00
key . magFilt ? GL_LINEAR : GL_NEAREST , MinFiltGL [ minKey ] , aniso ) ;
2012-11-01 16:19:01 +01:00
}
2019-10-24 22:40:26 +02:00
static void ConvertColors ( void * dstBuf , const void * srcBuf , Draw : : DataFormat dstFmt , int numPixels ) {
2013-05-26 13:31:58 -07:00
const u32 * src = ( const u32 * ) srcBuf ;
u32 * dst = ( u32 * ) dstBuf ;
2012-11-09 01:24:19 +01:00
switch ( dstFmt ) {
2019-10-24 23:01:45 +02:00
case Draw : : DataFormat : : R4G4B4A4_UNORM_PACK16 :
2015-05-17 13:45:30 -07:00
ConvertRGBA4444ToABGR4444 ( ( u16 * ) dst , ( const u16 * ) src , numPixels ) ;
2012-11-09 01:24:19 +01:00
break ;
2013-10-31 00:34:18 -07:00
// Final Fantasy 2 uses this heavily in animated textures.
2019-10-24 23:01:45 +02:00
case Draw : : DataFormat : : R5G5B5A1_UNORM_PACK16 :
2015-05-17 13:45:30 -07:00
ConvertRGBA5551ToABGR1555 ( ( u16 * ) dst , ( const u16 * ) src , numPixels ) ;
2012-11-09 01:24:19 +01:00
break ;
2019-10-24 23:01:45 +02:00
case Draw : : DataFormat : : R5G6B5_UNORM_PACK16 :
2015-05-17 13:45:30 -07:00
ConvertRGB565ToBGR565 ( ( u16 * ) dst , ( const u16 * ) src , numPixels ) ;
2012-11-09 01:24:19 +01:00
break ;
default :
2017-03-26 11:39:25 +02:00
// No need to convert RGBA8888, right order already
if ( dst ! = src )
memcpy ( dst , src , numPixels * sizeof ( u32 ) ) ;
2012-11-09 01:24:19 +01:00
break ;
}
}
2017-01-21 22:16:30 +01:00
void TextureCacheGLES : : StartFrame ( ) {
2022-08-05 13:27:55 +02:00
TextureCacheCommon : : StartFrame ( ) ;
2018-01-20 09:35:43 -08:00
GLRenderManager * renderManager = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
if ( ! lowMemoryMode_ & & renderManager - > SawOutOfMemory ( ) ) {
lowMemoryMode_ = true ;
decimationCounter_ = 0 ;
2023-04-06 00:34:50 +02:00
auto err = GetI18NCategory ( I18NCat : : ERRORS ) ;
2018-01-20 09:35:43 -08:00
if ( standardScaleFactor_ > 1 ) {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , err - > T ( " Warning: Video memory FULL, reducing upscaling and switching to slow caching mode " ) , 2.0f ) ;
2018-01-20 09:35:43 -08:00
} else {
2023-06-20 14:40:46 +02:00
g_OSD . Show ( OSDType : : MESSAGE_WARNING , err - > T ( " Warning: Video memory FULL, switching to slow caching mode " ) , 2.0f ) ;
2018-01-20 09:35:43 -08:00
}
}
2013-01-10 23:49:33 +01:00
}
2017-01-21 22:16:30 +01:00
void TextureCacheGLES : : UpdateCurrentClut ( GEPaletteFormat clutFormat , u32 clutBase , bool clutIndexIsSimple ) {
2015-07-20 22:18:26 +02:00
const u32 clutBaseBytes = clutFormat = = GE_CMODE_32BIT_ABGR8888 ? ( clutBase * sizeof ( u32 ) ) : ( clutBase * sizeof ( u16 ) ) ;
2013-06-15 23:04:43 -07:00
// Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier.
// If not, we're going to hash random data, which hopefully doesn't cause a performance issue.
2015-04-26 00:31:00 -07:00
//
// TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data.
// clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash
// unrelated old entries for small palettes.
// Adding clutBaseBytes may just be mitigating this for some usage patterns.
2015-04-26 00:43:36 -07:00
const u32 clutExtendedBytes = std : : min ( clutTotalBytes_ + clutBaseBytes , clutMaxBytes_ ) ;
2013-06-15 23:04:43 -07:00
2020-08-27 20:46:39 -07:00
if ( replacer_ . Enabled ( ) )
2020-08-28 01:15:22 -07:00
clutHash_ = XXH32 ( ( const char * ) clutBufRaw_ , clutExtendedBytes , 0xC0108888 ) ;
2020-08-27 20:46:39 -07:00
else
clutHash_ = XXH3_64bits ( ( const char * ) clutBufRaw_ , clutExtendedBytes ) & 0xFFFFFFFF ;
2013-05-26 12:45:53 -07:00
// Avoid a copy when we don't need to convert colors.
2017-03-26 11:39:25 +02:00
if ( clutFormat ! = GE_CMODE_32BIT_ABGR8888 ) {
2015-07-20 22:18:26 +02:00
const int numColors = clutFormat = = GE_CMODE_32BIT_ABGR8888 ? ( clutMaxBytes_ / sizeof ( u32 ) ) : ( clutMaxBytes_ / sizeof ( u16 ) ) ;
2014-08-19 22:28:26 -07:00
ConvertColors ( clutBufConverted_ , clutBufRaw_ , getClutDestFormat ( clutFormat ) , numColors ) ;
2013-05-26 12:45:53 -07:00
clutBuf_ = clutBufConverted_ ;
} else {
clutBuf_ = clutBufRaw_ ;
}
2013-05-12 10:57:41 -07:00
// Special optimization: fonts typically draw clut4 with just alpha values in a single color.
clutAlphaLinear_ = false ;
clutAlphaLinearColor_ = 0 ;
2015-07-29 11:38:42 +02:00
if ( clutFormat = = GE_CMODE_16BIT_ABGR4444 & & clutIndexIsSimple ) {
2014-09-09 00:53:01 -07:00
const u16_le * clut = GetCurrentClut < u16_le > ( ) ;
2013-05-12 10:57:41 -07:00
clutAlphaLinear_ = true ;
clutAlphaLinearColor_ = clut [ 15 ] & 0xFFF0 ;
for ( int i = 0 ; i < 16 ; + + i ) {
2016-01-01 09:02:16 -08:00
u16 step = clutAlphaLinearColor_ | i ;
if ( clut [ i ] ! = step ) {
2013-05-12 10:57:41 -07:00
clutAlphaLinear_ = false ;
break ;
}
}
}
2013-05-26 12:45:53 -07:00
2013-06-15 23:04:43 -07:00
clutLastFormat_ = gstate . clutformat ;
2013-05-11 15:45:17 -07:00
}
2017-02-19 23:07:00 +01:00
void TextureCacheGLES : : BindTexture ( TexCacheEntry * entry ) {
2022-08-24 11:26:07 +02:00
if ( ! entry ) {
render_ - > BindTexture ( 0 , nullptr ) ;
lastBoundTexture = nullptr ;
return ;
}
2017-02-19 23:07:00 +01:00
if ( entry - > textureName ! = lastBoundTexture ) {
2017-11-19 17:37:56 +01:00
render_ - > BindTexture ( 0 , entry - > textureName ) ;
2017-02-19 23:07:00 +01:00
lastBoundTexture = entry - > textureName ;
}
2022-07-29 12:25:04 +02:00
int maxLevel = ( entry - > status & TexCacheEntry : : STATUS_NO_MIPS ) ? 0 : entry - > maxLevel ;
2021-02-27 17:17:21 -08:00
SamplerCacheKey samplerKey = GetSamplingParams ( maxLevel , entry ) ;
2020-09-13 23:46:57 +02:00
ApplySamplingParams ( samplerKey ) ;
2022-09-11 14:14:18 +02:00
gstate_c . SetUseShaderDepal ( ShaderDepalMode : : OFF ) ;
2017-02-19 23:07:00 +01:00
}
2017-02-08 15:43:53 +01:00
void TextureCacheGLES : : Unbind ( ) {
2018-04-13 09:11:08 +02:00
render_ - > BindTexture ( TEX_SLOT_PSP_TEXTURE , nullptr ) ;
2023-02-24 21:53:12 +01:00
ForgetLastTexture ( ) ;
2013-09-01 11:40:35 -07:00
}
2022-08-24 09:31:47 +02:00
void TextureCacheGLES : : BindAsClutTexture ( Draw : : Texture * tex , bool smooth ) {
2022-08-05 11:44:09 +02:00
GLRTexture * glrTex = ( GLRTexture * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : TEXTURE_VIEW , tex ) ;
2022-08-05 10:00:27 +02:00
render_ - > BindTexture ( TEX_SLOT_CLUT , glrTex ) ;
2022-08-24 09:31:47 +02:00
render_ - > SetTextureSampler ( TEX_SLOT_CLUT , GL_CLAMP_TO_EDGE , GL_CLAMP_TO_EDGE , smooth ? GL_LINEAR : GL_NEAREST , smooth ? GL_LINEAR : GL_NEAREST , 0.0f ) ;
2022-08-05 10:00:27 +02:00
}
2018-03-25 10:49:28 +02:00
void TextureCacheGLES : : BuildTexture ( TexCacheEntry * const entry ) {
2022-07-28 12:59:30 +02:00
BuildTexturePlan plan ;
if ( ! PrepareBuildTexture ( plan , entry ) ) {
// We're screwed?
2016-05-01 11:17:55 -07:00
return ;
}
2020-12-10 11:18:43 +01:00
_assert_ ( ! entry - > textureName ) ;
2022-07-28 11:18:47 +02:00
// GLES2 doesn't have support for a "Max lod" which is critical as PSP games often
// don't specify mips all the way down. As a result, we either need to manually generate
// the bottom few levels or rely on OpenGL's autogen mipmaps instead, which might not
// be as good quality as the game's own (might even be better in some cases though).
2022-09-01 15:02:51 +02:00
int tw = plan . createW ;
int th = plan . createH ;
2020-12-10 11:18:43 +01:00
2022-07-28 11:18:47 +02:00
Draw : : DataFormat dstFmt = GetDestFormat ( GETextureFormat ( entry - > format ) , gstate . getClutPaletteFormat ( ) ) ;
2023-03-18 11:45:26 +01:00
if ( plan . doReplace ) {
2023-03-10 14:16:14 +01:00
plan . replaced - > GetSize ( plan . baseLevelSrc , & tw , & th ) ;
2023-03-09 00:05:24 +01:00
dstFmt = plan . replaced - > Format ( ) ;
2022-09-01 15:02:51 +02:00
} else if ( plan . scaleFactor > 1 | | plan . saveTexture ) {
2022-07-30 19:04:12 +02:00
dstFmt = Draw : : DataFormat : : R8G8B8A8_UNORM ;
2022-09-14 23:35:15 +02:00
} else if ( plan . decodeToClut8 ) {
dstFmt = Draw : : DataFormat : : R8_UNORM ;
2022-07-30 14:48:17 +02:00
}
2022-07-30 21:33:24 +02:00
if ( plan . depth = = 1 ) {
2023-01-12 19:45:40 +01:00
entry - > textureName = render_ - > CreateTexture ( GL_TEXTURE_2D , tw , th , 1 , plan . levelsToCreate ) ;
2022-07-30 21:33:24 +02:00
} else {
2023-01-12 19:45:40 +01:00
entry - > textureName = render_ - > CreateTexture ( GL_TEXTURE_3D , tw , th , plan . depth , 1 ) ;
2022-07-30 21:33:24 +02:00
}
2022-07-28 11:18:47 +02:00
2022-07-29 12:59:43 +02:00
// Apply some additional compatibility checks.
if ( plan . levelsToLoad > 1 ) {
// Avoid PowerVR driver bug
if ( plan . w > 1 & & plan . h > 1 & & ! ( plan . h > plan . w & & draw_ - > GetBugs ( ) . Has ( Draw : : Bugs : : PVR_GENMIPMAP_HEIGHT_GREATER ) ) ) { // Really! only seems to fail if height > width
// It's ok to generate mipmaps beyond the loaded levels.
2014-12-14 01:24:01 +01:00
} else {
2022-07-29 12:59:43 +02:00
plan . levelsToCreate = plan . levelsToLoad ;
2014-12-14 01:24:01 +01:00
}
2022-07-29 12:59:43 +02:00
}
2022-10-17 08:30:27 +02:00
if ( ! gstate_c . Use ( GPU_USE_TEXTURE_LOD_CONTROL ) ) {
2022-08-09 17:26:39 +02:00
// If the mip chain is not full..
if ( plan . levelsToCreate ! = plan . maxPossibleLevels ) {
// We need to avoid creating mips at all, or generate them all - can't be incomplete
// on this hardware (strict OpenGL rules).
plan . levelsToCreate = 1 ;
plan . levelsToLoad = 1 ;
entry - > status | = TexCacheEntry : : STATUS_NO_MIPS ;
}
2013-04-03 07:33:14 +08:00
}
2022-07-30 21:33:24 +02:00
if ( plan . depth = = 1 ) {
for ( int i = 0 ; i < plan . levelsToLoad ; i + + ) {
int srcLevel = i = = 0 ? plan . baseLevelSrc : i ;
2022-07-30 19:04:12 +02:00
2022-08-30 11:56:14 +02:00
int mipWidth ;
int mipHeight ;
plan . GetMipSize ( i , & mipWidth , & mipHeight ) ;
2022-07-30 19:04:12 +02:00
2022-07-30 21:33:24 +02:00
u8 * data = nullptr ;
int stride = 0 ;
2023-03-12 00:14:06 +01:00
int dataSize ;
bool bc = false ;
2022-07-30 19:04:12 +02:00
2023-03-18 11:45:26 +01:00
if ( plan . doReplace ) {
2023-03-12 00:14:06 +01:00
int blockSize = 0 ;
if ( Draw : : DataFormatIsBlockCompressed ( plan . replaced - > Format ( ) , & blockSize ) ) {
stride = mipWidth * 4 ;
2023-03-17 13:58:36 +01:00
dataSize = plan . replaced - > GetLevelDataSizeAfterCopy ( i ) ;
2023-03-12 00:14:06 +01:00
bc = true ;
} else {
int bpp = ( int ) Draw : : DataFormatSizeInBytes ( plan . replaced - > Format ( ) ) ;
2023-09-27 16:42:07 +02:00
stride = mipWidth * bpp ;
2023-03-12 00:14:06 +01:00
dataSize = stride * mipHeight ;
}
2022-07-30 21:33:24 +02:00
} else {
2023-03-12 00:14:06 +01:00
int bpp = 0 ;
2022-07-30 21:33:24 +02:00
if ( plan . scaleFactor > 1 ) {
2022-08-30 11:56:14 +02:00
bpp = 4 ;
2022-07-30 21:33:24 +02:00
} else {
2022-09-14 23:35:15 +02:00
bpp = ( int ) Draw : : DataFormatSizeInBytes ( dstFmt ) ;
2022-07-30 21:33:24 +02:00
}
2023-09-27 16:42:07 +02:00
stride = mipWidth * bpp ;
2023-03-12 00:14:06 +01:00
dataSize = stride * mipHeight ;
2022-07-30 19:04:12 +02:00
}
2022-07-30 21:33:24 +02:00
2023-03-12 00:14:06 +01:00
data = ( u8 * ) AllocateAlignedMemory ( dataSize , 16 ) ;
2022-08-30 11:56:14 +02:00
2022-07-30 21:33:24 +02:00
if ( ! data ) {
2022-08-30 11:56:14 +02:00
ERROR_LOG ( G3D , " Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d) " , mipWidth , mipHeight ) ;
2022-07-30 21:33:24 +02:00
return ;
}
2023-03-17 13:58:36 +01:00
LoadTextureLevel ( * entry , data , dataSize , stride , plan , srcLevel , dstFmt , TexDecodeFlags : : REVERSE_COLORS ) ;
2022-07-30 21:33:24 +02:00
// NOTE: TextureImage takes ownership of data, so we don't free it afterwards.
2022-08-30 11:56:14 +02:00
render_ - > TextureImage ( entry - > textureName , i , mipWidth , mipHeight , 1 , dstFmt , data , GLRAllocType : : ALIGNED ) ;
2022-07-30 19:04:12 +02:00
}
2022-07-30 21:33:24 +02:00
bool genMips = plan . levelsToCreate > plan . levelsToLoad ;
render_ - > FinalizeTexture ( entry - > textureName , plan . levelsToLoad , genMips ) ;
} else {
2022-09-14 23:35:15 +02:00
int bpp = ( int ) Draw : : DataFormatSizeInBytes ( dstFmt ) ;
2022-07-30 21:33:24 +02:00
int stride = bpp * ( plan . w * plan . scaleFactor ) ;
int levelStride = stride * ( plan . h * plan . scaleFactor ) ;
2023-03-17 13:58:36 +01:00
size_t dataSize = levelStride * plan . depth ;
u8 * data = ( u8 * ) AllocateAlignedMemory ( dataSize , 16 ) ;
2022-07-30 21:33:24 +02:00
memset ( data , 0 , levelStride * plan . depth ) ;
u8 * p = data ;
for ( int i = 0 ; i < plan . depth ; i + + ) {
2023-03-17 13:58:36 +01:00
LoadTextureLevel ( * entry , p , dataSize , stride , plan , i , dstFmt , TexDecodeFlags : : REVERSE_COLORS ) ;
2022-07-30 21:33:24 +02:00
p + = levelStride ;
2022-07-30 19:04:12 +02:00
}
2022-07-30 21:33:24 +02:00
render_ - > TextureImage ( entry - > textureName , 0 , plan . w * plan . scaleFactor , plan . h * plan . scaleFactor , plan . depth , dstFmt , data , GLRAllocType : : ALIGNED ) ;
2022-07-30 19:04:12 +02:00
2022-07-30 21:33:24 +02:00
// Signal that we support depth textures so use it as one.
entry - > status | = TexCacheEntry : : STATUS_3D ;
render_ - > FinalizeTexture ( entry - > textureName , 1 , false ) ;
2022-07-29 12:59:43 +02:00
}
2020-12-10 10:28:48 +01:00
2023-03-18 11:45:26 +01:00
if ( plan . doReplace ) {
2022-07-28 12:59:30 +02:00
entry - > SetAlphaStatus ( TexCacheEntry : : TexStatus ( plan . replaced - > AlphaStatus ( ) ) ) ;
2016-04-30 13:44:31 -07:00
}
2013-02-08 00:04:34 +01:00
}
2024-04-05 17:04:31 +03:00
Draw : : DataFormat TextureCacheGLES : : GetDestFormat ( GETextureFormat format , GEPaletteFormat clutFormat ) {
2013-10-08 15:00:48 +02:00
switch ( format ) {
case GE_TFMT_CLUT4 :
case GE_TFMT_CLUT8 :
case GE_TFMT_CLUT16 :
case GE_TFMT_CLUT32 :
return getClutDestFormat ( clutFormat ) ;
case GE_TFMT_4444 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R4G4B4A4_UNORM_PACK16 ;
2013-10-08 15:00:48 +02:00
case GE_TFMT_5551 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R5G5B5A1_UNORM_PACK16 ;
2013-10-08 15:00:48 +02:00
case GE_TFMT_5650 :
2019-10-24 23:01:45 +02:00
return Draw : : DataFormat : : R5G6B5_UNORM_PACK16 ;
2013-10-08 15:00:48 +02:00
case GE_TFMT_8888 :
case GE_TFMT_DXT1 :
case GE_TFMT_DXT3 :
case GE_TFMT_DXT5 :
default :
2019-10-24 22:40:26 +02:00
return Draw : : DataFormat : : R8G8B8A8_UNORM ;
2013-10-08 15:00:48 +02:00
}
}
2022-10-10 22:35:42 -07:00
bool TextureCacheGLES : : GetCurrentTextureDebug ( GPUDebugBuffer & buffer , int level , bool * isFramebuffer ) {
2023-02-24 21:53:12 +01:00
ForgetLastTexture ( ) ;
2020-09-20 20:35:42 +02:00
SetTexture ( ) ;
2020-08-23 21:29:15 -07:00
if ( ! nextTexture_ ) {
2022-10-10 22:35:42 -07:00
return GetCurrentFramebufferTextureDebug ( buffer , isFramebuffer ) ;
2020-08-23 21:29:15 -07:00
}
2018-01-19 22:41:18 -08:00
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
TexCacheEntry * entry = nextTexture_ ;
2018-06-11 14:56:25 -07:00
// We might need a render pass to set the sampling params, unfortunately. Otherwise BuildTexture may crash.
2020-06-02 09:51:38 +02:00
framebufferManagerGL_ - > RebindFramebuffer ( " RebindFramebuffer - GetCurrentTextureDebug " ) ;
2017-10-18 13:03:49 +02:00
ApplyTexture ( ) ;
2018-01-19 22:41:18 -08:00
GLRenderManager * renderManager = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
// Not a framebuffer, so let's assume these are right.
2018-07-29 11:07:29 -07:00
// TODO: But they may definitely not be, if the texture was scaled.
2017-10-18 13:03:49 +02:00
int w = gstate . getTextureWidth ( level ) ;
int h = gstate . getTextureHeight ( level ) ;
2020-08-23 08:24:46 -07:00
bool result = entry - > textureName ! = nullptr ;
if ( result ) {
buffer . Allocate ( w , h , GE_FORMAT_8888 , false ) ;
renderManager - > CopyImageToMemorySync ( entry - > textureName , level , 0 , 0 , w , h , Draw : : DataFormat : : R8G8B8A8_UNORM , ( uint8_t * ) buffer . GetData ( ) , w , " GetCurrentTextureDebug " ) ;
2020-08-23 21:29:15 -07:00
} else {
ERROR_LOG ( G3D , " Failed to get debug texture: texture is null " ) ;
2020-08-23 08:24:46 -07:00
}
2018-01-19 22:41:18 -08:00
gstate_c . Dirty ( DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS ) ;
2020-06-02 09:51:38 +02:00
framebufferManager_ - > RebindFramebuffer ( " RebindFramebuffer - GetCurrentTextureDebug " ) ;
2017-10-18 13:03:49 +02:00
2022-10-10 22:35:42 -07:00
* isFramebuffer = false ;
2020-08-23 08:24:46 -07:00
return result ;
2017-10-18 13:03:49 +02:00
}
2017-12-07 14:56:19 +01:00
2018-04-05 11:25:49 +02:00
void TextureCacheGLES : : DeviceLost ( ) {
2022-08-22 12:28:46 +02:00
textureShaderCache_ - > DeviceLost ( ) ;
2018-04-05 11:25:49 +02:00
Clear ( false ) ;
draw_ = nullptr ;
render_ = nullptr ;
}
2017-12-07 14:56:19 +01:00
void TextureCacheGLES : : DeviceRestore ( Draw : : DrawContext * draw ) {
draw_ = draw ;
2018-04-05 20:17:19 +02:00
render_ = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
2022-08-22 12:28:46 +02:00
textureShaderCache_ - > DeviceRestore ( draw ) ;
2017-12-07 14:56:19 +01:00
}
2022-09-14 08:42:25 +02:00
void * TextureCacheGLES : : GetNativeTextureView ( const TexCacheEntry * entry ) {
GLRTexture * tex = entry - > textureName ;
return ( void * ) tex ;
}