WIP directx9 renderer
This commit is contained in:
parent
4a8ce39bfd
commit
f107d380b9
|
@ -865,6 +865,21 @@ if(USE_VULKAN AND NOT APPLE)
|
|||
core/rend/vulkan/vulkan_renderer.cpp)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/dx9/d3d_renderer.h
|
||||
core/rend/dx9/d3d_renderer.cpp
|
||||
core/rend/dx9/d3d_shaders.h
|
||||
core/rend/dx9/d3d_shaders.cpp
|
||||
core/rend/dx9/d3d_texture.h
|
||||
core/rend/dx9/d3d_texture.cpp
|
||||
core/rend/dx9/dxcontext.h
|
||||
core/rend/dx9/dxcontext.cpp
|
||||
core/rend/dx9/imgui_impl_dx9.h
|
||||
core/rend/dx9/imgui_impl_dx9.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3dx9)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/rec-ARM/ngen_arm.S core/rec-ARM/rec_arm.cpp)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
|
||||
|
|
|
@ -315,11 +315,22 @@ extern OptionString AudioBackend;
|
|||
class RendererOption : public Option<RenderType> {
|
||||
public:
|
||||
RendererOption()
|
||||
#ifdef _WIN32
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#else
|
||||
: Option<RenderType>("pvr.rend", RenderType::OpenGL) {}
|
||||
#endif
|
||||
|
||||
bool isOpenGL() const {
|
||||
return value == RenderType::OpenGL || value == RenderType::OpenGL_OIT;
|
||||
}
|
||||
bool isVulkan() const {
|
||||
return value == RenderType::Vulkan || value == RenderType::Vulkan_OIT;
|
||||
}
|
||||
bool isDirectX() const {
|
||||
return value == RenderType::DirectX9;
|
||||
}
|
||||
|
||||
void set(RenderType v)
|
||||
{
|
||||
newValue = v;
|
||||
|
|
|
@ -65,6 +65,7 @@ ifdef FOR_LINUX
|
|||
endif
|
||||
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_MODULES += rend/dx9/
|
||||
ifndef UNIT_TESTS
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/winmain.cpp
|
||||
endif
|
||||
|
|
|
@ -248,6 +248,7 @@ Renderer* rend_GL4();
|
|||
Renderer* rend_norend();
|
||||
Renderer* rend_Vulkan();
|
||||
Renderer* rend_OITVulkan();
|
||||
Renderer* rend_DirectX9();
|
||||
|
||||
static void rend_create_renderer()
|
||||
{
|
||||
|
@ -273,6 +274,11 @@ static void rend_create_renderer()
|
|||
case RenderType::Vulkan_OIT:
|
||||
renderer = rend_OITVulkan();
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
case RenderType::DirectX9:
|
||||
renderer = rend_DirectX9();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@ void ta_vtx_SoftReset();
|
|||
void DYNACALL ta_vtx_data32(const SQBuffer *data);
|
||||
void ta_vtx_data(const SQBuffer *data, u32 size);
|
||||
|
||||
bool ta_parse_vdrc(TA_context* ctx);
|
||||
bool ta_parse_vdrc(TA_context *ctx, bool bgraColors = false);
|
||||
|
||||
class TaTypeLut
|
||||
{
|
||||
|
|
|
@ -86,8 +86,7 @@ static f32 f16(u16 v)
|
|||
|
||||
#define vdrc vd_rc
|
||||
|
||||
//Splitter function (normally ta_dma_main , modified for split dma's)
|
||||
|
||||
template<int Red = 0, int Green = 1, int Blue = 2, int Alpha = 3>
|
||||
class FifoSplitter
|
||||
{
|
||||
static const u32 *ta_type_lut;
|
||||
|
@ -719,10 +718,10 @@ private:
|
|||
#define glob_param_bdc(pp) glob_param_bdc_( (TA_PolyParam0*)pp)
|
||||
|
||||
#define poly_float_color_(to,a,r,g,b) \
|
||||
to[0] = float_to_satu8(r); \
|
||||
to[1] = float_to_satu8(g); \
|
||||
to[2] = float_to_satu8(b); \
|
||||
to[3] = float_to_satu8(a);
|
||||
to[Red] = float_to_satu8(r); \
|
||||
to[Green] = float_to_satu8(g); \
|
||||
to[Blue] = float_to_satu8(b); \
|
||||
to[Alpha] = float_to_satu8(a);
|
||||
|
||||
|
||||
#define poly_float_color(to,src) \
|
||||
|
@ -869,17 +868,17 @@ private:
|
|||
#define vert_packed_color_(to,src) \
|
||||
{ \
|
||||
u32 t=src; \
|
||||
to[2] = (u8)(t);t>>=8;\
|
||||
to[1] = (u8)(t);t>>=8;\
|
||||
to[0] = (u8)(t);t>>=8;\
|
||||
to[3] = (u8)(t); \
|
||||
to[Blue] = (u8)(t);t>>=8;\
|
||||
to[Green] = (u8)(t);t>>=8;\
|
||||
to[Red] = (u8)(t);t>>=8;\
|
||||
to[Alpha] = (u8)(t); \
|
||||
}
|
||||
|
||||
#define vert_float_color_(to,a,r,g,b) \
|
||||
to[0] = float_to_satu8(r); \
|
||||
to[1] = float_to_satu8(g); \
|
||||
to[2] = float_to_satu8(b); \
|
||||
to[3] = float_to_satu8(a);
|
||||
to[Red] = float_to_satu8(r); \
|
||||
to[Green] = float_to_satu8(g); \
|
||||
to[Blue] = float_to_satu8(b); \
|
||||
to[Alpha] = float_to_satu8(a);
|
||||
|
||||
//Macros to make thins easier ;)
|
||||
#define vert_packed_color(to,src) \
|
||||
|
@ -895,34 +894,32 @@ private:
|
|||
//Intensity is clamped before the mul, as well as on face color to work the same as the hardware. [Fixes red dog]
|
||||
|
||||
#define vert_face_base_color(baseint) \
|
||||
{ u32 satint=float_to_satu8(vtx->baseint); \
|
||||
cv->col[0] = FaceBaseColor[0]*satint/256; \
|
||||
cv->col[1] = FaceBaseColor[1]*satint/256; \
|
||||
cv->col[2] = FaceBaseColor[2]*satint/256; \
|
||||
cv->col[3] = FaceBaseColor[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->baseint); \
|
||||
cv->col[Red] = FaceBaseColor[Red] * satint / 256; \
|
||||
cv->col[Green] = FaceBaseColor[Green] * satint / 256; \
|
||||
cv->col[Blue] = FaceBaseColor[Blue] * satint / 256; \
|
||||
cv->col[Alpha] = FaceBaseColor[Alpha]; }
|
||||
|
||||
#define vert_face_offs_color(offsint) \
|
||||
{ u32 satint=float_to_satu8(vtx->offsint); \
|
||||
cv->spc[0] = FaceOffsColor[0]*satint/256; \
|
||||
cv->spc[1] = FaceOffsColor[1]*satint/256; \
|
||||
cv->spc[2] = FaceOffsColor[2]*satint/256; \
|
||||
cv->spc[3] = FaceOffsColor[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->offsint); \
|
||||
cv->spc[Red] = FaceOffsColor[Red] * satint / 256; \
|
||||
cv->spc[Green] = FaceOffsColor[Green] * satint / 256; \
|
||||
cv->spc[Blue] = FaceOffsColor[Blue] * satint / 256; \
|
||||
cv->spc[Alpha] = FaceOffsColor[Alpha]; }
|
||||
|
||||
#define vert_face_base_color1(baseint) \
|
||||
{ u32 satint=float_to_satu8(vtx->baseint); \
|
||||
cv->col1[0] = FaceBaseColor1[0]*satint/256; \
|
||||
cv->col1[1] = FaceBaseColor1[1]*satint/256; \
|
||||
cv->col1[2] = FaceBaseColor1[2]*satint/256; \
|
||||
cv->col1[3] = FaceBaseColor1[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->baseint); \
|
||||
cv->col1[Red] = FaceBaseColor1[Red] * satint / 256; \
|
||||
cv->col1[Green] = FaceBaseColor1[Green] * satint / 256; \
|
||||
cv->col1[Blue] = FaceBaseColor1[Blue] * satint / 256; \
|
||||
cv->col1[Alpha] = FaceBaseColor1[Alpha]; }
|
||||
|
||||
#define vert_face_offs_color1(offsint) \
|
||||
{ u32 satint=float_to_satu8(vtx->offsint); \
|
||||
cv->spc1[0] = FaceOffsColor1[0]*satint/256; \
|
||||
cv->spc1[1] = FaceOffsColor1[1]*satint/256; \
|
||||
cv->spc1[2] = FaceOffsColor1[2]*satint/256; \
|
||||
cv->spc1[3] = FaceOffsColor1[3]; }
|
||||
|
||||
//vert_float_color_(cv->spc,FaceOffsColor[3],FaceOffsColor[0]*satint/256,FaceOffsColor[1]*satint/256,FaceOffsColor[2]*satint/256); }
|
||||
{ u32 satint = float_to_satu8(vtx->offsint); \
|
||||
cv->spc1[Red] = FaceOffsColor1[Red] * satint / 256; \
|
||||
cv->spc1[Green] = FaceOffsColor1[Green] * satint / 256; \
|
||||
cv->spc1[Blue] = FaceOffsColor1[Blue] * satint / 256; \
|
||||
cv->spc1[Alpha] = FaceOffsColor1[Alpha]; }
|
||||
|
||||
|
||||
//(Non-Textured, Packed Color)
|
||||
|
@ -1172,9 +1169,9 @@ private:
|
|||
|
||||
d_pp->texid = -1;
|
||||
|
||||
if (d_pp->pcw.Texture) {
|
||||
d_pp->texid = renderer->GetTexture(d_pp->tsp,d_pp->tcw);
|
||||
}
|
||||
if (d_pp->pcw.Texture)
|
||||
d_pp->texid = renderer->GetTexture(d_pp->tsp, d_pp->tcw);
|
||||
|
||||
d_pp->tcw1.full = -1;
|
||||
d_pp->tsp1.full = -1;
|
||||
d_pp->texid1 = -1;
|
||||
|
@ -1374,7 +1371,8 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
const u32 *FifoSplitter::ta_type_lut;
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
const u32 *FifoSplitter<Red, Green, Blue, Alpha>::ta_type_lut;
|
||||
|
||||
TaTypeLut::TaTypeLut()
|
||||
{
|
||||
|
@ -1382,8 +1380,8 @@ TaTypeLut::TaTypeLut()
|
|||
{
|
||||
PCW pcw;
|
||||
pcw.obj_ctrl = i;
|
||||
u32 rv = FifoSplitter::poly_data_type_id(pcw);
|
||||
u32 type = FifoSplitter::poly_header_type_size(pcw);
|
||||
u32 rv = FifoSplitter<>::poly_data_type_id(pcw);
|
||||
u32 type = FifoSplitter<>::poly_header_type_size(pcw);
|
||||
|
||||
if (type & 0x80)
|
||||
rv |= SZ64 << 30;
|
||||
|
@ -1399,7 +1397,8 @@ TaTypeLut::TaTypeLut()
|
|||
static bool ClearZBeforePass(int pass_number);
|
||||
static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax);
|
||||
|
||||
FifoSplitter TAFifo0;
|
||||
FifoSplitter<> TAParser;
|
||||
FifoSplitter<2, 1, 0, 3> TAParserDX;
|
||||
|
||||
//
|
||||
// Check if a vertex has huge x,y,z values or negative z
|
||||
|
@ -1540,7 +1539,7 @@ static void fix_texture_bleeding(const List<PolyParam> *list)
|
|||
}
|
||||
}
|
||||
|
||||
bool ta_parse_vdrc(TA_context* ctx)
|
||||
bool ta_parse_vdrc(TA_context* ctx, bool bgraColors)
|
||||
{
|
||||
ctx->rend_inuse.lock();
|
||||
bool rv=false;
|
||||
|
@ -1548,7 +1547,10 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
vd_ctx = ctx;
|
||||
vd_rc = vd_ctx->rend;
|
||||
|
||||
TAFifo0.vdec_init();
|
||||
if (bgraColors)
|
||||
TAParserDX.vdec_init();
|
||||
else
|
||||
TAParser.vdec_init();
|
||||
|
||||
bool empty_context = true;
|
||||
int op_poly_count = 0;
|
||||
|
@ -1636,7 +1638,8 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
|
||||
//decode a vertex in the native pvr format
|
||||
//used for bg poly
|
||||
static void decode_pvr_vertex(u32 base,u32 ptr,Vertex* cv)
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
void decode_pvr_vertex(u32 base, u32 ptr, Vertex* cv)
|
||||
{
|
||||
//ISP
|
||||
//TSP
|
||||
|
@ -1773,7 +1776,10 @@ void FillBGP(TA_context* ctx)
|
|||
float scale_x= (SCALER_CTL.hscale) ? 2.f:1.f; //if AA hack the hacked pos value hacks
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
decode_pvr_vertex(strip_base,vertex_ptr,&cv[i]);
|
||||
if (config::RendererType.isDirectX())
|
||||
decode_pvr_vertex<2, 1, 0, 3>(strip_base,vertex_ptr,&cv[i]);
|
||||
else
|
||||
decode_pvr_vertex<0, 1, 2, 3>(strip_base,vertex_ptr,&cv[i]);
|
||||
vertex_ptr+=strip_vs;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,39 +92,80 @@ void palette_update()
|
|||
pal_needs_update = false;
|
||||
palette_updated = true;
|
||||
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
if (!config::RendererType.isDirectX())
|
||||
{
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
{
|
||||
palette16_ram[i] = ARGB1555(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB1555_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = Unpacker1555::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker1555_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB565(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB565_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker565_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB4444(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB4444_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = Unpacker4444::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker4444_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB8888(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB8888_32(PALETTE_RAM[i]);
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerRGBA8888::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = UnpackerRGBA8888_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
{
|
||||
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker1555_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker565_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker4444_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerARGB8888::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = UnpackerNop<u32>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < 64; i++)
|
||||
pal_hash_16[i] = XXH32(&PALETTE_RAM[i << 4], 16 * 4, 7);
|
||||
|
@ -312,28 +353,38 @@ struct PvrTexInfo
|
|||
int bpp; //4/8 for pal. 16 for yuv, rgb, argb
|
||||
TextureType type;
|
||||
// Conversion to 16 bpp
|
||||
TexConvFP *PL;
|
||||
TexConvFP *TW;
|
||||
TexConvFP *VQ;
|
||||
TexConvFP PL;
|
||||
TexConvFP TW;
|
||||
TexConvFP VQ;
|
||||
// Conversion to 32 bpp
|
||||
TexConvFP32 *PL32;
|
||||
TexConvFP32 *TW32;
|
||||
TexConvFP32 *VQ32;
|
||||
TexConvFP32 PL32;
|
||||
TexConvFP32 TW32;
|
||||
TexConvFP32 VQ32;
|
||||
// Conversion to 8 bpp (palette)
|
||||
TexConvFP8 *TW8;
|
||||
TexConvFP8 TW8;
|
||||
};
|
||||
|
||||
static const PvrTexInfo format[8] =
|
||||
{ // name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b) Palette (8b)
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32, nullptr }, //1555
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32, nullptr }, //565
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //4444
|
||||
{"yuv", 16, TextureType::_8888, nullptr, nullptr, nullptr, texYUV422_PL, texYUV422_TW, texYUV422_VQ, nullptr }, //yuv
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //bump map
|
||||
{"pal4", 4, TextureType::_5551, nullptr, texPAL4_TW, texPAL4_VQ, nullptr, texPAL4_TW32, texPAL4_VQ32, texPAL4PT_TW }, //pal4
|
||||
{"pal8", 8, TextureType::_5551, nullptr, texPAL8_TW, texPAL8_VQ, nullptr, texPAL8_TW32, texPAL8_VQ32, texPAL8PT_TW }, //pal8
|
||||
{"ns/1555", 0}, // Not supported (1555)
|
||||
};
|
||||
#define TEX_CONV_TABLE \
|
||||
const PvrTexInfo pvrTexInfo[8] = \
|
||||
{ /* name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b) Palette (8b) */ \
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32, nullptr }, \
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32, nullptr }, \
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, \
|
||||
{"yuv", 16, TextureType::_8888, nullptr, nullptr, nullptr, texYUV422_PL, texYUV422_TW, texYUV422_VQ, nullptr }, \
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, \
|
||||
{"pal4", 4, TextureType::_5551, nullptr, texPAL4_TW, texPAL4_VQ, nullptr, texPAL4_TW32, texPAL4_VQ32, texPAL4PT_TW }, \
|
||||
{"pal8", 8, TextureType::_5551, nullptr, texPAL8_TW, texPAL8_VQ, nullptr, texPAL8_TW32, texPAL8_VQ32, texPAL8PT_TW }, \
|
||||
{"ns/1555", 0}, \
|
||||
}
|
||||
|
||||
namespace opengl {
|
||||
TEX_CONV_TABLE;
|
||||
}
|
||||
namespace directx {
|
||||
TEX_CONV_TABLE;
|
||||
}
|
||||
#undef TEX_CONV_TABLE
|
||||
static const PvrTexInfo *pvrTexInfo = opengl::pvrTexInfo;
|
||||
|
||||
static const u32 VQMipPoint[11] =
|
||||
{
|
||||
|
@ -432,7 +483,7 @@ void BaseTextureCacheData::Create()
|
|||
custom_load_in_progress = 0;
|
||||
|
||||
//decode info from tsp/tcw into the texture struct
|
||||
tex = &format[tcw.PixelFmt == PixelReserved ? Pixel1555 : tcw.PixelFmt]; //texture format table entry
|
||||
tex = &pvrTexInfo[tcw.PixelFmt == PixelReserved ? Pixel1555 : tcw.PixelFmt]; //texture format table entry
|
||||
|
||||
sa_tex = (tcw.TexAddr << 3) & VRAM_MASK; //texture start address
|
||||
sa = sa_tex; //data texture start address (modified for MIPs, as needed)
|
||||
|
@ -624,7 +675,7 @@ void BaseTextureCacheData::Update()
|
|||
vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8;
|
||||
if (tcw.PixelFmt == PixelYUV && i == 0)
|
||||
// Special case for YUV at 1x1 LoD
|
||||
format[Pixel565].TW32(&pb32, &vram[vram_addr], 1, 1);
|
||||
pvrTexInfo[Pixel565].TW32(&pb32, &vram[vram_addr], 1, 1);
|
||||
else
|
||||
texconv32(&pb32, &vram[vram_addr], 1 << i, 1 << i);
|
||||
}
|
||||
|
@ -742,6 +793,11 @@ void BaseTextureCacheData::CheckCustomTexture()
|
|||
}
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::SetDirectXColorOrder(bool enabled) {
|
||||
pvrTexInfo = enabled ? directx::pvrTexInfo : opengl::pvrTexInfo;
|
||||
}
|
||||
|
||||
template<typename Packer = RGBAPacker>
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
||||
{
|
||||
width = (FB_R_SIZE.fb_x_size + 1) << 1; // in 16-bit words
|
||||
|
@ -787,7 +843,7 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
}
|
||||
|
||||
pb.init(width, height);
|
||||
u8 *dst = (u8*)pb.data();
|
||||
u32 *dst = (u32 *)pb.data();
|
||||
|
||||
switch (FB_R_CTRL.fb_depth)
|
||||
{
|
||||
|
@ -797,10 +853,11 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u16 src = pvr_read32p<u16>(addr);
|
||||
*dst++ = (((src >> 10) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 5) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(
|
||||
(((src >> 10) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 5) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
0xff);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -813,10 +870,11 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u16 src = pvr_read32p<u16>(addr);
|
||||
*dst++ = (((src >> 11) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 5) & 0x3F) << 2) + (FB_R_CTRL.fb_concat & 3);
|
||||
*dst++ = (((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(
|
||||
(((src >> 11) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 5) & 0x3F) << 2) + (FB_R_CTRL.fb_concat & 3),
|
||||
(((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
0xFF);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -828,33 +886,21 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i += 4)
|
||||
{
|
||||
u32 src = pvr_read32p<u32>(addr);
|
||||
*dst++ = src >> 16;
|
||||
*dst++ = src >> 8;
|
||||
*dst++ = src;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src >> 16, src >> 8, src, 0xff);
|
||||
addr += 4;
|
||||
if (i + 1 >= width)
|
||||
break;
|
||||
u32 src2 = pvr_read32p<u32>(addr);
|
||||
*dst++ = src2 >> 8;
|
||||
*dst++ = src2;
|
||||
*dst++ = src >> 24;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src2 >> 8, src2, src >> 24, 0xff);
|
||||
addr += 4;
|
||||
if (i + 2 >= width)
|
||||
break;
|
||||
u32 src3 = pvr_read32p<u32>(addr);
|
||||
*dst++ = src3;
|
||||
*dst++ = src2 >> 24;
|
||||
*dst++ = src2 >> 16;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src3, src2 >> 24, src2 >> 16, 0xff);
|
||||
addr += 4;
|
||||
if (i + 3 >= width)
|
||||
break;
|
||||
*dst++ = src3 >> 24;
|
||||
*dst++ = src3 >> 16;
|
||||
*dst++ = src3 >> 8;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src3 >> 24, src3 >> 16, src3 >> 8, 0xff);
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
}
|
||||
|
@ -865,10 +911,7 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u32 src = pvr_read32p<u32>(addr);
|
||||
*dst++ = src >> 16;
|
||||
*dst++ = src >> 8;
|
||||
*dst++ = src;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src >> 16, src >> 8, src, 0xff);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -876,6 +919,8 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
break;
|
||||
}
|
||||
}
|
||||
template void ReadFramebuffer<RGBAPacker>(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
template void ReadFramebuffer<BGRAPacker>(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,8 @@ extern bool palette_updated;
|
|||
|
||||
extern u32 detwiddle[2][11][1024];
|
||||
|
||||
void palette_update();
|
||||
|
||||
template<class pixel_type>
|
||||
class PixelBuffer
|
||||
{
|
||||
|
@ -120,407 +122,289 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void palette_update();
|
||||
|
||||
#define clamp(minv, maxv, x) ((x) < (minv) ? (minv) : (x) > (maxv) ? (maxv) : (x))
|
||||
|
||||
// Unpack to 16-bit word
|
||||
// Open GL
|
||||
struct RGBAPacker {
|
||||
static u32 pack(u8 r, u8 g, u8 b, u8 a) {
|
||||
return r | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
};
|
||||
// DirectX
|
||||
struct BGRAPacker {
|
||||
static u32 pack(u8 r, u8 g, u8 b, u8 a) {
|
||||
return b | (g << 8) | (r << 16) | (a << 24);
|
||||
}
|
||||
};
|
||||
|
||||
#define ARGB1555( word ) ( ((word>>15)&1) | (((word>>10) & 0x1F)<<11) | (((word>>5) & 0x1F)<<6) | (((word>>0) & 0x1F)<<1) )
|
||||
|
||||
#define ARGB565( word ) ( (((word>>0)&0x1F)<<0) | (((word>>5)&0x3F)<<5) | (((word>>11)&0x1F)<<11) )
|
||||
|
||||
#define ARGB4444( word ) ( (((word>>0)&0xF)<<4) | (((word>>4)&0xF)<<8) | (((word>>8)&0xF)<<12) | (((word>>12)&0xF)<<0) )
|
||||
|
||||
#define ARGB8888( word ) ( (((word>>4)&0xF)<<4) | (((word>>12)&0xF)<<8) | (((word>>20)&0xF)<<12) | (((word>>28)&0xF)<<0) )
|
||||
|
||||
// Unpack to 32-bit word
|
||||
|
||||
#define ARGB1555_32( word ) ( ((word & 0x8000) ? 0xFF000000 : 0) | \
|
||||
(((word >> 10) & 0x1F) << 3) | (((word >> 12) & 0x7) << 0) | \
|
||||
(((word >> 5) & 0x1F) << 11) | (((word >> 7) & 0x7) << 8) | \
|
||||
(((word >> 0) & 0x1F) << 19) | (((word >> 2) & 0x7) << 16) )
|
||||
|
||||
#define ARGB565_32( word ) ( (((word >> 11) & 0x1F) << 3) | (((word >> 13) & 0x7) << 0) | \
|
||||
(((word >> 5) & 0x3F) << 10) | (((word >> 9) & 0x3) << 8) | \
|
||||
(((word >> 0) & 0x1F) << 19) | (((word >> 2) & 0x7) << 16) | \
|
||||
0xFF000000 )
|
||||
|
||||
#define ARGB4444_32( word ) ( (((word >> 12) & 0xF) << 28) | (((word >> 12) & 0xF) << 24) | \
|
||||
(((word >> 8) & 0xF) << 4) | (((word >> 8) & 0xF) << 0) | \
|
||||
(((word >> 4) & 0xF) << 12) | (((word >> 4) & 0xF) << 8) | \
|
||||
(((word >> 0) & 0xF) << 20) | (((word >> 0) & 0xF) << 16) )
|
||||
|
||||
#define ARGB8888_32( word ) ( ((word >> 0) & 0xFF000000) | (((word >> 16) & 0xFF) << 0) | (((word >> 8) & 0xFF) << 8) | ((word & 0xFF) << 16) )
|
||||
|
||||
inline static u32 YUV422(s32 Y,s32 Yu,s32 Yv)
|
||||
template<typename Packer>
|
||||
inline static u32 YUV422(s32 Y, s32 Yu, s32 Yv)
|
||||
{
|
||||
Yu-=128;
|
||||
Yv-=128;
|
||||
Yu -= 128;
|
||||
Yv -= 128;
|
||||
|
||||
s32 R = Y + Yv*11/8; // Y + (Yv-128) * (11/8) ?
|
||||
s32 G = Y - (Yu*11 + Yv*22)/32; // Y - (Yu-128) * (11/8) * 0.25 - (Yv-128) * (11/8) * 0.5 ?
|
||||
s32 B = Y + Yu*110/64; // Y + (Yu-128) * (11/8) * 1.25 ?
|
||||
s32 R = Y + Yv * 11 / 8; // Y + (Yv-128) * (11/8) ?
|
||||
s32 G = Y - (Yu * 11 + Yv * 22) / 32; // Y - (Yu-128) * (11/8) * 0.25 - (Yv-128) * (11/8) * 0.5 ?
|
||||
s32 B = Y + Yu * 110 / 64; // Y + (Yu-128) * (11/8) * 1.25 ?
|
||||
|
||||
return clamp(0, 255, R) | (clamp(0, 255, G) << 8) | (clamp(0, 255, B) << 16) | 0xFF000000;
|
||||
return Packer::pack(clamp(0, 255, R), clamp(0, 255, G), clamp(0, 255, B), 0xFF);
|
||||
}
|
||||
|
||||
#define twop(x,y,bcx,bcy) (detwiddle[0][bcy][x]+detwiddle[1][bcx][y])
|
||||
|
||||
//pixel convertors !
|
||||
#define pixelcvt_start_base(name,x,y,type) \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
static const u32 ypp=y; \
|
||||
__forceinline static void Convert(PixelBuffer<type>* pb,u8* data) \
|
||||
{
|
||||
template<typename Pixel>
|
||||
struct UnpackerNop {
|
||||
using unpacked_type = Pixel;
|
||||
static Pixel unpack(Pixel word) {
|
||||
return word;
|
||||
}
|
||||
};
|
||||
// ARGB1555 to RGBA5551
|
||||
struct Unpacker1555 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u16 word) {
|
||||
return ((word >> 15) & 1) | (((word >> 10) & 0x1F) << 11) | (((word >> 5) & 0x1F) << 6) | (((word >> 0) & 0x1F) << 1);
|
||||
}
|
||||
};
|
||||
// ARGB4444 to RGBA4444
|
||||
struct Unpacker4444 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u16 word) {
|
||||
return (((word >> 0) & 0xF) << 4) | (((word >> 4) & 0xF) << 8) | (((word >> 8) & 0xF) << 12) | (((word >> 12) & 0xF) << 0);
|
||||
}
|
||||
};
|
||||
// ARGB8888 to RGBA4444
|
||||
struct UnpackerRGBA8888 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u32 word) {
|
||||
return (((word >> 4) & 0xF) << 4) | (((word >> 12) & 0xF) << 8) | (((word >> 20) & 0xF) << 12) | (((word >> 28) & 0xF) << 0);
|
||||
}
|
||||
};
|
||||
// ARGB8888 to ARGB4444
|
||||
struct UnpackerARGB8888 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u32 word) {
|
||||
return (((word >> 4) & 0xF) << 0) | (((word >> 12) & 0xF) << 4) | (((word >> 20) & 0xF) << 8) | (((word >> 28) & 0xF) << 12);
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_start(name,x,y) pixelcvt_start_base(name, x, y, u16)
|
||||
#define pixelcvt32_start(name,x,y) pixelcvt_start_base(name, x, y, u32)
|
||||
template <typename Packer>
|
||||
struct Unpacker1555_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 10) & 0x1F) << 3) | ((word >> 12) & 7),
|
||||
(((word >> 5) & 0x1F) << 3) | ((word >> 7) & 7),
|
||||
(((word >> 0) & 0x1F) << 3) | ((word >> 2) & 7),
|
||||
(word & 0x8000) ? 0xFF : 0);
|
||||
}
|
||||
};
|
||||
template <typename Packer>
|
||||
struct Unpacker565_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 11) & 0x1F) << 3) | ((word >> 13) & 7),
|
||||
(((word >> 5) & 0x3F) << 2) | ((word >> 9) & 3),
|
||||
(((word >> 0) & 0x1F) << 13) | ((word >> 2) & 7),
|
||||
0xFF);
|
||||
}
|
||||
};
|
||||
template <typename Packer>
|
||||
struct Unpacker4444_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 8) & 0xF) << 4) | ((word >> 8) & 0xF),
|
||||
(((word >> 4) & 0xF) << 4) | ((word >> 4) & 0xF),
|
||||
(((word >> 0) & 0xF) << 4) | ((word >> 0) & 0xF),
|
||||
(((word >> 12) & 0xF) << 4) | ((word >> 12) & 0xF));
|
||||
}
|
||||
};
|
||||
template <typename Packer>
|
||||
struct UnpackerRGBA8888_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u32 word) {
|
||||
return Packer::pack(
|
||||
(word >> 16) & 0xFF,
|
||||
(word >> 8) & 0xFF,
|
||||
(word >> 0) & 0xFF,
|
||||
(word >> 24) & 0xFF);
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_size_start(name, x, y) template<class pixel_size> \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
static const u32 ypp=y; \
|
||||
__forceinline static void Convert(PixelBuffer<pixel_size>* pb,u8* data) \
|
||||
template<typename Unpacker>
|
||||
struct ConvertPlanar
|
||||
{
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 1;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u16 *p_in = (u16 *)data;
|
||||
pb->prel(0, Unpacker::unpack(p_in[0]));
|
||||
pb->prel(1, Unpacker::unpack(p_in[1]));
|
||||
pb->prel(2, Unpacker::unpack(p_in[2]));
|
||||
pb->prel(3, Unpacker::unpack(p_in[3]));
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_end } }
|
||||
#define pixelcvt_next(name,x,y) pixelcvt_end; pixelcvt_start(name,x,y)
|
||||
//
|
||||
//Non twiddled
|
||||
//
|
||||
// 16-bit pixel buffer
|
||||
pixelcvt_start(conv565_PL,4,1)
|
||||
template<typename Packer>
|
||||
struct ConvertPlanarYUV
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB565(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB565(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB565(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB565(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv1555_PL,4,1)
|
||||
using unpacked_type = u32;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 1;
|
||||
static void Convert(PixelBuffer<u32> *pb, u8 *data)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u32 *p_in = (u32 *)data;
|
||||
|
||||
|
||||
s32 Y0 = (p_in[0] >> 8) & 255; //
|
||||
s32 Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
s32 Y1 = (p_in[0] >> 24) & 255; //p_in[3]
|
||||
s32 Yv = (p_in[0] >> 16) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(1, YUV422<Packer>(Y1, Yu, Yv));
|
||||
|
||||
//next 4 bytes
|
||||
p_in += 1;
|
||||
|
||||
Y0 = (p_in[0] >> 8) & 255; //
|
||||
Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
Y1 = (p_in[0] >> 24) & 255; //p_in[3]
|
||||
Yv = (p_in[0] >> 16) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(2, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(3, YUV422<Packer>(Y1, Yu, Yv));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Unpacker>
|
||||
struct ConvertTwiddle
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB1555(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB1555(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB1555(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB1555(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv4444_PL,4,1)
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 2;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u16 *p_in = (u16 *)data;
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0]));
|
||||
pb->prel(0, 1, Unpacker::unpack(p_in[1]));
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[2]));
|
||||
pb->prel(1, 1, Unpacker::unpack(p_in[3]));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Packer>
|
||||
struct ConvertTwiddleYUV
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB4444(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB4444(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB4444(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB4444(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
using unpacked_type = u32;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 2;
|
||||
static void Convert(PixelBuffer<u32> *pb, u8 *data)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u16* p_in = (u16 *)data;
|
||||
|
||||
// 32-bit pixel buffer
|
||||
pixelcvt32_start(conv565_PL32,4,1)
|
||||
s32 Y0 = (p_in[0] >> 8) & 255; //
|
||||
s32 Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
s32 Y1 = (p_in[2] >> 8) & 255; //p_in[3]
|
||||
s32 Yv = (p_in[2] >> 0) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0, 0, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(1, 0, YUV422<Packer>(Y1, Yu, Yv));
|
||||
|
||||
//next 4 bytes
|
||||
//p_in+=2;
|
||||
|
||||
Y0 = (p_in[1] >> 8) & 255; //
|
||||
Yu = (p_in[1] >> 0) & 255; //p_in[0]
|
||||
Y1 = (p_in[3] >> 8) & 255; //p_in[3]
|
||||
Yv = (p_in[3] >> 0) & 255; //p_in[2]
|
||||
|
||||
//0,1
|
||||
pb->prel(0, 1, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,1
|
||||
pb->prel(1, 1, YUV422<Packer>(Y1, Yu, Yv));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Pixel>
|
||||
struct UnpackerPalToRgb {
|
||||
using unpacked_type = Pixel;
|
||||
static Pixel unpack(u8 col)
|
||||
{
|
||||
u32 *pal = sizeof(Pixel) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
return pal[col];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Unpacker>
|
||||
struct ConvertTwiddlePal4
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB565_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB565_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB565_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB565_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv1555_PL32,4,1)
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 4;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u8 *p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(0, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(1, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(0, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(0, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(1, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(1, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(2, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(2, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(3, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(3, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(2, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(2, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(3, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(3, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Unpacker>
|
||||
struct ConvertTwiddlePal8
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB1555_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB1555_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB1555_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB1555_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv4444_PL32,4,1)
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB4444_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB4444_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB4444_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB4444_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(convYUV_PL,4,1)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u32* p_in=(u32*)data;
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 4;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(0, 1, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 1, Unpacker::unpack(p_in[0])); p_in++;
|
||||
|
||||
s32 Y0 = (p_in[0]>>8) &255; //
|
||||
s32 Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
s32 Y1 = (p_in[0]>>24) &255; //p_in[3]
|
||||
s32 Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
p_in+=1;
|
||||
|
||||
Y0 = (p_in[0]>>8) &255; //
|
||||
Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
Y1 = (p_in[0]>>24) &255; //p_in[3]
|
||||
Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(2,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(3,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
//
|
||||
//twiddled
|
||||
//
|
||||
// 16-bit pixel buffer
|
||||
pixelcvt_start(conv565_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB565(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB565(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB565(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB565(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv1555_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB1555(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB1555(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB1555(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB1555(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv4444_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB4444(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB4444(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB4444(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB4444(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// 32-bit pixel buffer
|
||||
pixelcvt32_start(conv565_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB565_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB565_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB565_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB565_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv1555_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB1555_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB1555_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB1555_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB1555_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv4444_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB4444_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB4444_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB4444_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB4444_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pixelcvt32_start(convYUV_TW,2,2)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
|
||||
|
||||
s32 Y0 = (p_in[0]>>8) &255; //
|
||||
s32 Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
s32 Y1 = (p_in[2]>>8) &255; //p_in[3]
|
||||
s32 Yv = (p_in[2]>>0) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,0,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
//p_in+=2;
|
||||
|
||||
Y0 = (p_in[1]>>8) &255; //
|
||||
Yu = (p_in[1]>>0) &255; //p_in[0]
|
||||
Y1 = (p_in[3]>>8) &255; //p_in[3]
|
||||
Yv = (p_in[3]>>0) &255; //p_in[2]
|
||||
|
||||
//0,1
|
||||
pb->prel(0,1,YUV422(Y0,Yu,Yv));
|
||||
//1,1
|
||||
pb->prel(1,1,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// 16-bit && 32-bit pixel buffers
|
||||
pixelcvt_size_start(convPAL4_TW,4,4)
|
||||
{
|
||||
u8* p_in=(u8*)data;
|
||||
u32* pal= sizeof(pixel_size) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
|
||||
pb->prel(0,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(0,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(1,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(1,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(0,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(0,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(1,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(1,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(2,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(2,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(3,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(3,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(2,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(2,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(3,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(3,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 4bpp -> 8bpp
|
||||
pixelcvt_size_start(convPAL4PT_TW, 4, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0] & 0xF);
|
||||
pb->prel(0, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 0, p_in[0] & 0xF);
|
||||
pb->prel(1, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0] & 0xF);
|
||||
pb->prel(0, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 2, p_in[0] & 0xF);
|
||||
pb->prel(1, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 0, p_in[0] & 0xF);
|
||||
pb->prel(2, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 0, p_in[0] & 0xF);
|
||||
pb->prel(3, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 2, p_in[0] & 0xF);
|
||||
pb->prel(2, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 2, p_in[0] & 0xF);
|
||||
pb->prel(3, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pixelcvt_size_start(convPAL8_TW,2,4)
|
||||
{
|
||||
u8* p_in=(u8*)data;
|
||||
u32* pal= sizeof(pixel_size) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
|
||||
pb->prel(0,0,pal[p_in[0]]);p_in++;
|
||||
pb->prel(0,1,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,0,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,1,pal[p_in[0]]);p_in++;
|
||||
|
||||
pb->prel(0,2,pal[p_in[0]]);p_in++;
|
||||
pb->prel(0,3,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,2,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,3,pal[p_in[0]]);p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 8bpp -> 8bpp (untwiddle only)
|
||||
pixelcvt_size_start(convPAL8PT_TW, 2, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0]); p_in++;
|
||||
pb->prel(0, 1, p_in[0]); p_in++;
|
||||
pb->prel(1, 0, p_in[0]); p_in++;
|
||||
pb->prel(1, 1, p_in[0]); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0]); p_in++;
|
||||
pb->prel(0, 3, p_in[0]); p_in++;
|
||||
pb->prel(1, 2, p_in[0]); p_in++;
|
||||
pb->prel(1, 3, p_in[0]); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pb->prel(0, 2, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(0, 3, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 2, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 3, Unpacker::unpack(p_in[0])); p_in++;
|
||||
}
|
||||
};
|
||||
|
||||
//handler functions
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_PL(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_PL(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
pb->amove(0,0);
|
||||
|
||||
|
@ -541,8 +425,8 @@ void texture_PL(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_TW(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_TW(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
pb->amove(0, 0);
|
||||
|
||||
|
@ -564,8 +448,8 @@ void texture_TW(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_VQ(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_VQ(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
p_in += 256 * 4 * 2; // Skip VQ codebook
|
||||
pb->amove(0, 0);
|
||||
|
@ -587,51 +471,98 @@ void texture_VQ(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
typedef void (*TexConvFP)(PixelBuffer<u16>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
typedef void (*TexConvFP8)(PixelBuffer<u8>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
typedef void (*TexConvFP32)(PixelBuffer<u32>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
|
||||
//Planar
|
||||
#define tex565_PL texture_PL<conv565_PL, u16>
|
||||
#define tex1555_PL texture_PL<conv1555_PL, u16>
|
||||
#define tex4444_PL texture_PL<conv4444_PL, u16>
|
||||
#define texYUV422_PL texture_PL<convYUV_PL, u32>
|
||||
#define texBMP_PL tex4444_PL
|
||||
|
||||
#define tex565_PL32 texture_PL<conv565_PL32, u32>
|
||||
#define tex1555_PL32 texture_PL<conv1555_PL32, u32>
|
||||
#define tex4444_PL32 texture_PL<conv4444_PL32, u32>
|
||||
|
||||
constexpr TexConvFP tex565_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
//Twiddle
|
||||
#define tex565_TW texture_TW<conv565_TW, u16>
|
||||
#define tex1555_TW texture_TW<conv1555_TW, u16>
|
||||
#define tex4444_TW texture_TW<conv4444_TW, u16>
|
||||
#define texYUV422_TW texture_TW<convYUV_TW, u32>
|
||||
#define texBMP_TW tex4444_TW
|
||||
#define texPAL4_TW texture_TW<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_TW texture_TW<convPAL8_TW<u16>, u16>
|
||||
#define texPAL4_TW32 texture_TW<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_TW32 texture_TW<convPAL8_TW<u32>, u32>
|
||||
#define texPAL4PT_TW texture_TW<convPAL4PT_TW<u8>, u8>
|
||||
#define texPAL8PT_TW texture_TW<convPAL8PT_TW<u8>, u8>
|
||||
|
||||
#define tex565_TW32 texture_TW<conv565_TW32, u32>
|
||||
#define tex1555_TW32 texture_TW<conv1555_TW32, u32>
|
||||
#define tex4444_TW32 texture_TW<conv4444_TW32, u32>
|
||||
|
||||
constexpr TexConvFP tex565_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
// Palette
|
||||
constexpr TexConvFP texPAL4_TW = texture_TW<ConvertTwiddlePal4<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP texPAL8_TW = texture_TW<ConvertTwiddlePal8<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP32 texPAL4_TW32 = texture_TW<ConvertTwiddlePal4<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP32 texPAL8_TW32 = texture_TW<ConvertTwiddlePal8<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP8 texPAL4PT_TW = texture_TW<ConvertTwiddlePal4<UnpackerNop<u8>>>;
|
||||
constexpr TexConvFP8 texPAL8PT_TW = texture_TW<ConvertTwiddlePal8<UnpackerNop<u8>>>;
|
||||
//VQ
|
||||
#define tex565_VQ texture_VQ<conv565_TW, u16>
|
||||
#define tex1555_VQ texture_VQ<conv1555_TW, u16>
|
||||
#define tex4444_VQ texture_VQ<conv4444_TW, u16>
|
||||
#define texYUV422_VQ texture_VQ<convYUV_TW, u32>
|
||||
#define texBMP_VQ tex4444_VQ
|
||||
constexpr TexConvFP tex565_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
// According to the documentation, a texture cannot be compressed and use
|
||||
// a palette at the same time. However the hardware displays them
|
||||
// just fine.
|
||||
#define texPAL4_VQ texture_VQ<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_VQ texture_VQ<convPAL8_TW<u16>, u16>
|
||||
constexpr TexConvFP texPAL4_VQ = texture_VQ<ConvertTwiddlePal4<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP texPAL8_VQ = texture_VQ<ConvertTwiddlePal8<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP32 texPAL4_VQ32 = texture_VQ<ConvertTwiddlePal4<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP32 texPAL8_VQ32 = texture_VQ<ConvertTwiddlePal8<UnpackerPalToRgb<u32>>>;
|
||||
|
||||
#define tex565_VQ32 texture_VQ<conv565_TW32, u32>
|
||||
#define tex1555_VQ32 texture_VQ<conv1555_TW32, u32>
|
||||
#define tex4444_VQ32 texture_VQ<conv4444_TW32, u32>
|
||||
#define texPAL4_VQ32 texture_VQ<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_VQ32 texture_VQ<convPAL8_TW<u32>, u32>
|
||||
namespace opengl {
|
||||
// Open GL
|
||||
|
||||
//Planar
|
||||
constexpr TexConvFP tex1555_PL = texture_PL<ConvertPlanar<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_PL = texture_PL<ConvertPlanar<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_PL = tex4444_PL;
|
||||
constexpr TexConvFP32 texYUV422_PL = texture_PL<ConvertPlanarYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_PL32 = texture_PL<ConvertPlanar<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_PL32 = texture_PL<ConvertPlanar<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_PL32 = texture_PL<ConvertPlanar<Unpacker4444_32<RGBAPacker>>>;
|
||||
|
||||
//Twiddle
|
||||
constexpr TexConvFP tex1555_TW = texture_TW<ConvertTwiddle<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_TW = texture_TW<ConvertTwiddle<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_TW = tex4444_TW;
|
||||
constexpr TexConvFP32 texYUV422_TW = texture_TW<ConvertTwiddleYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_TW32 = texture_TW<ConvertTwiddle<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_TW32 = texture_TW<ConvertTwiddle<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_TW32 = texture_TW<ConvertTwiddle<Unpacker4444_32<RGBAPacker>>>;
|
||||
|
||||
//VQ
|
||||
constexpr TexConvFP tex1555_VQ = texture_VQ<ConvertTwiddle<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_VQ = texture_VQ<ConvertTwiddle<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_VQ = tex4444_VQ;
|
||||
constexpr TexConvFP32 texYUV422_VQ = texture_VQ<ConvertTwiddleYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_VQ32 = texture_VQ<ConvertTwiddle<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_VQ32 = texture_VQ<ConvertTwiddle<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_VQ32 = texture_VQ<ConvertTwiddle<Unpacker4444_32<RGBAPacker>>>;
|
||||
}
|
||||
|
||||
namespace directx {
|
||||
// DirectX
|
||||
|
||||
//Planar
|
||||
constexpr TexConvFP tex1555_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_PL = tex4444_PL;
|
||||
constexpr TexConvFP32 texYUV422_PL = texture_PL<ConvertPlanarYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_PL32 = texture_PL<ConvertPlanar<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_PL32 = texture_PL<ConvertPlanar<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_PL32 = texture_PL<ConvertPlanar<Unpacker4444_32<BGRAPacker>>>;
|
||||
|
||||
//Twiddle
|
||||
constexpr TexConvFP tex1555_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_TW = tex4444_TW;
|
||||
constexpr TexConvFP32 texYUV422_TW = texture_TW<ConvertTwiddleYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_TW32 = texture_TW<ConvertTwiddle<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_TW32 = texture_TW<ConvertTwiddle<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_TW32 = texture_TW<ConvertTwiddle<Unpacker4444_32<BGRAPacker>>>;
|
||||
|
||||
//VQ
|
||||
constexpr TexConvFP tex1555_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_VQ = tex4444_VQ;
|
||||
constexpr TexConvFP32 texYUV422_VQ = texture_VQ<ConvertTwiddleYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_VQ32 = texture_VQ<ConvertTwiddle<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_VQ32 = texture_VQ<ConvertTwiddle<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_VQ32 = texture_VQ<ConvertTwiddle<Unpacker4444_32<BGRAPacker>>>;
|
||||
}
|
||||
|
||||
struct vram_block
|
||||
{
|
||||
|
@ -652,10 +583,6 @@ void libCore_vramlock_Lock(u32 start_offset, u32 end_offset, BaseTextureCacheDat
|
|||
void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool has_alpha);
|
||||
|
||||
struct PvrTexInfo;
|
||||
template <class pixel_type> class PixelBuffer;
|
||||
typedef void TexConvFP(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
typedef void TexConvFP8(PixelBuffer<u8>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
typedef void TexConvFP32(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
enum class TextureType { _565, _5551, _4444, _8888, _8 };
|
||||
|
||||
class BaseTextureCacheData
|
||||
|
@ -673,9 +600,9 @@ public:
|
|||
u32 size; //size, in bytes, in vram
|
||||
|
||||
const PvrTexInfo* tex;
|
||||
TexConvFP *texconv;
|
||||
TexConvFP32 *texconv32;
|
||||
TexConvFP8 *texconv8;
|
||||
TexConvFP texconv;
|
||||
TexConvFP32 texconv32;
|
||||
TexConvFP8 texconv8;
|
||||
|
||||
u32 dirty;
|
||||
vram_block* lock_block;
|
||||
|
@ -748,6 +675,7 @@ public:
|
|||
&& !tcw.MipMapped
|
||||
&& !tcw.VQ_Comp;
|
||||
}
|
||||
static void SetDirectXColorOrder(bool enabled);
|
||||
};
|
||||
|
||||
template<typename Texture>
|
||||
|
@ -829,6 +757,7 @@ protected:
|
|||
const TCW TCWTextureCacheMask = { { 0x1FFFFF, 0, 0, 1, 7, 1, 1 } };
|
||||
};
|
||||
|
||||
template<typename Packer = RGBAPacker>
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl = -1, u32 linestride = -1);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <array>
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include <d3d9.h>
|
||||
#include "dxcontext.h"
|
||||
#include "rend/transform_matrix.h"
|
||||
#include "d3d_texture.h"
|
||||
#include "d3d_shaders.h"
|
||||
#include "rend/sorter.h"
|
||||
|
||||
class RenderStateCache
|
||||
{
|
||||
IDirect3DDevice9 *device = nullptr;
|
||||
std::array<DWORD, 210> renderState;
|
||||
std::array<DWORD, 14> sampler0State;
|
||||
IDirect3DVertexShader9 *vertexShader = nullptr;
|
||||
IDirect3DPixelShader9 *pixelShader = nullptr;
|
||||
IDirect3DBaseTexture9 *texture = nullptr;
|
||||
|
||||
public:
|
||||
void setDevice(IDirect3DDevice9 *device) {
|
||||
this->device = device;
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
renderState.fill(0xfefefefe);
|
||||
sampler0State.fill(0xfefefefe);
|
||||
vertexShader = nullptr;
|
||||
pixelShader = nullptr;
|
||||
texture = nullptr;
|
||||
}
|
||||
|
||||
HRESULT SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
|
||||
{
|
||||
if ((u32)state < renderState.size())
|
||||
{
|
||||
if (renderState[state] == value)
|
||||
return S_OK;
|
||||
renderState[state] = value;
|
||||
}
|
||||
return device->SetRenderState(state, value);
|
||||
}
|
||||
HRESULT SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
|
||||
{
|
||||
if (sampler == 0 && (u32)type < sampler0State.size())
|
||||
{
|
||||
if (sampler0State[type] == value)
|
||||
return S_OK;
|
||||
sampler0State[type] = value;
|
||||
}
|
||||
return device->SetSamplerState(sampler, type, value);
|
||||
}
|
||||
HRESULT SetVertexShader(IDirect3DVertexShader9 *pShader)
|
||||
{
|
||||
if (pShader == vertexShader)
|
||||
return S_OK;
|
||||
vertexShader = pShader;
|
||||
return device->SetVertexShader(pShader);
|
||||
}
|
||||
HRESULT SetPixelShader(IDirect3DPixelShader9 *pShader)
|
||||
{
|
||||
if (pShader == pixelShader)
|
||||
return S_OK;
|
||||
pixelShader = pShader;
|
||||
return device->SetPixelShader(pShader);
|
||||
}
|
||||
HRESULT SetTexture(DWORD stage, IDirect3DBaseTexture9 *pTexture)
|
||||
{
|
||||
if (stage == 0)
|
||||
{
|
||||
if (pTexture == texture)
|
||||
return S_OK;
|
||||
texture = pTexture;
|
||||
}
|
||||
return device->SetTexture(stage, pTexture);
|
||||
}
|
||||
};
|
||||
|
||||
struct D3DRenderer : public Renderer
|
||||
{
|
||||
bool Init() override;
|
||||
void Resize(int w, int h) override;
|
||||
void Term() override;
|
||||
bool Process(TA_context* ctx) override;
|
||||
bool Render() override;
|
||||
bool RenderLastFrame() override;
|
||||
bool Present() override { return true; }
|
||||
void DrawOSD(bool clear_screen) override;
|
||||
u64 GetTexture(TSP tsp, TCW tcw) override;
|
||||
|
||||
private:
|
||||
enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount };
|
||||
|
||||
void drawStrips();
|
||||
template <u32 Type, bool SortingEnabled>
|
||||
void drawList(const List<PolyParam>& gply, int first, int count);
|
||||
template <u32 Type, bool SortingEnabled>
|
||||
void setGPState(const PolyParam *gp, u32 cflip = 0);
|
||||
bool ensureVertexBufferSize(ComPtr<IDirect3DVertexBuffer9>& buffer, u32& currentSize, u32 minSize);
|
||||
bool ensureIndexBufferSize(ComPtr<IDirect3DIndexBuffer9>& buffer, u32& currentSize, u32 minSize);
|
||||
void updatePaletteTexture();
|
||||
void updateFogTexture();
|
||||
void renderFramebuffer();
|
||||
void readDCFramebuffer();
|
||||
void renderDCFramebuffer();
|
||||
void sortTriangles(int first, int count);
|
||||
void drawSorted(bool multipass);
|
||||
void setMVS_Mode(ModifierVolumeMode mv_mode, ISP_Modvol ispc);
|
||||
void drawModVols(int first, int count);
|
||||
void setProvokingVertices();
|
||||
void setTexMode(D3DSAMPLERSTATETYPE state, u32 clamp, u32 mirror);
|
||||
|
||||
RenderStateCache devCache;
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
ComPtr<IDirect3DVertexBuffer9> vertexBuffer;
|
||||
u32 vertexBufferSize = 0;
|
||||
ComPtr<IDirect3DVertexBuffer9> modvolBuffer;
|
||||
u32 modvolBufferSize = 0;
|
||||
ComPtr<IDirect3DIndexBuffer9> indexBuffer;
|
||||
u32 indexBufferSize = 0;
|
||||
ComPtr<IDirect3DIndexBuffer9> sortedTriIndexBuffer;
|
||||
u32 sortedTriIndexBufferSize = 0;
|
||||
ComPtr<IDirect3DVertexDeclaration9> mainVtxDecl;
|
||||
ComPtr<IDirect3DVertexDeclaration9> modVolVtxDecl;
|
||||
|
||||
ComPtr<IDirect3DTexture9> framebufferTexture;
|
||||
ComPtr<IDirect3DSurface9> framebufferSurface;
|
||||
ComPtr<IDirect3DSurface9> backbuffer;
|
||||
ComPtr<IDirect3DTexture9> paletteTexture;
|
||||
ComPtr<IDirect3DTexture9> fogTexture;
|
||||
ComPtr<IDirect3DTexture9> dcfbTexture;
|
||||
ComPtr<IDirect3DSurface9> dcfbSurface;
|
||||
ComPtr<IDirect3DTexture9> rttTexture;
|
||||
ComPtr<IDirect3DSurface9> rttSurface;
|
||||
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
TransformMatrix<true, true> matrices;
|
||||
D3DTextureCache texCache;
|
||||
std::vector<SortTrigDrawParam> pidx_sort;
|
||||
D3DShaders shaders;
|
||||
};
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "d3d_shaders.h"
|
||||
|
||||
// FIXME
|
||||
#define SHADER_DEBUG D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION
|
||||
|
||||
const char *VertexShader = R"(
|
||||
struct vertex_in
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float4 spc : COLOR1;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct vertex_out
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float4 uv : TEXCOORD0;
|
||||
float4 col : COLOR0;
|
||||
float4 spc : COLOR1;
|
||||
};
|
||||
|
||||
float4x4 normal_matrix : register(c0);
|
||||
|
||||
vertex_out main(in vertex_in vin)
|
||||
{
|
||||
vertex_out vo;
|
||||
#if pp_Gouraud == 1
|
||||
vo.col = vin.col * vin.pos.z;
|
||||
vo.spc = vin.spc * vin.pos.z;
|
||||
#else
|
||||
// flat shading: no interpolation
|
||||
vo.col = vin.col;
|
||||
vo.spc = vin.spc;
|
||||
#endif
|
||||
vo.uv = float4(vin.uv * vin.pos.z, 0, vin.pos.z);
|
||||
vo.pos = mul(normal_matrix, vin.pos);
|
||||
|
||||
vo.pos.w = 1.0f;
|
||||
vo.pos.z = 0;
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
const char *PixelShader = R"(
|
||||
|
||||
#define PI 3.1415926f
|
||||
|
||||
struct pixel
|
||||
{
|
||||
float4 uv : TEXCOORD0;
|
||||
float4 col : COLOR0;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offs : COLOR1;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
sampler2D samplr : register(s0);
|
||||
sampler2D tex_pal : register(s1);
|
||||
sampler2D fog_table : register(s2);
|
||||
|
||||
float4 palette_index : register(c0);
|
||||
float4 FOG_COL_VERT : register(c1);
|
||||
float4 FOG_COL_RAM : register(c2);
|
||||
float4 FOG_DENSITY : register(c3);
|
||||
float4 ClipTest : register(c4);
|
||||
float4 trilinear_alpha : register(c5);
|
||||
float4 fog_clamp_min : register(c6);
|
||||
float4 fog_clamp_max : register(c7);
|
||||
|
||||
float fog_mode2(float w)
|
||||
{
|
||||
float z = clamp(w * FOG_DENSITY.x, 1.0f, 255.9999f);
|
||||
float exp = floor(log2(z));
|
||||
float m = z * 16.0f / pow(2.0, exp) - 16.0f;
|
||||
float idx = floor(m) + exp * 16.0f + 0.5f;
|
||||
float4 fog_coef = tex2D(fog_table, float2(idx / 128.0f, 0.75f - (m - floor(m)) / 2.0f));
|
||||
return fog_coef.a;
|
||||
}
|
||||
|
||||
float4 fog_clamp(float4 col)
|
||||
{
|
||||
#if FogClamping == 1
|
||||
return clamp(col, fog_clamp_min, fog_clamp_max);
|
||||
#else
|
||||
return col;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
float4 palettePixel(float4 coords)
|
||||
{
|
||||
int color_idx = int(floor(tex2Dproj(samplr, coords).a * 255.0f + 0.5f) + palette_index.x);
|
||||
float2 c = float2((fmod(float(color_idx), 32.0f) * 2.0f + 1.0f) / 64.0f, (float(color_idx / 32) * 2.0f + 1.0f) / 64.0f);
|
||||
return tex2D(tex_pal, c);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct PSO
|
||||
{
|
||||
float4 col : COLOR0;
|
||||
float z : DEPTH;
|
||||
};
|
||||
|
||||
PSO main(in pixel inpix)
|
||||
{
|
||||
// Clip inside the box
|
||||
/* TODO
|
||||
#if pp_ClipInside == 1
|
||||
if (VPOS.x >= pp_ClipTest.x && VPOS.x <= pp_ClipTest.z
|
||||
&& VPOS.y >= pp_ClipTest.y && VPOS.y <= pp_ClipTest.w)
|
||||
discard;
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if pp_Gouraud == 1
|
||||
float4 color = inpix.col / inpix.uv.w;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offset = inpix.offs / inpix.uv.w;
|
||||
#endif
|
||||
#else
|
||||
float4 color = inpix.col;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offset = inpix.offs;
|
||||
#endif
|
||||
#endif
|
||||
#if pp_UseAlpha == 0
|
||||
color.a = 1.0f;
|
||||
#endif
|
||||
#if pp_FogCtrl == 3
|
||||
color = float4(FOG_COL_RAM.rgb, fog_mode2(inpix.uv.w));
|
||||
#endif
|
||||
#if pp_Texture == 1
|
||||
{
|
||||
#if pp_Palette == 0
|
||||
float4 texcol = tex2Dproj(samplr, inpix.uv);
|
||||
#else
|
||||
float4 texcol = palettePixel(inpix.uv);
|
||||
#endif
|
||||
|
||||
#if pp_BumpMap == 1
|
||||
float s = PI / 2.0f * (texcol.a * 15.0f * 16.0f + texcol.r * 15.0f) / 255.0f;
|
||||
float r = 2.0f * PI * (texcol.g * 15.0f * 16.0f + texcol.b * 15.0f) / 255.0f;
|
||||
texcol[3] = clamp(offset.a + offset.r * sin(s) + offset.g * cos(s) * cos(r - 2.0f * PI * offset.b), 0.0f, 1.0f);
|
||||
texcol.rgb = float3(1.0f, 1.0f, 1.0f);
|
||||
#else
|
||||
#if pp_IgnoreTexA == 1
|
||||
texcol.a = 1.0f;
|
||||
#endif
|
||||
#endif
|
||||
#if pp_ShadInstr == 0
|
||||
color = texcol;
|
||||
#endif
|
||||
#if pp_ShadInstr == 1
|
||||
color.rgb *= texcol.rgb;
|
||||
color.a = texcol.a;
|
||||
#endif
|
||||
#if pp_ShadInstr == 2
|
||||
color.rgb = lerp(color.rgb, texcol.rgb, texcol.a);
|
||||
#endif
|
||||
#if pp_ShadInstr == 3
|
||||
color *= texcol;
|
||||
#endif
|
||||
|
||||
#if pp_Offset == 1 && pp_BumpMap == 0
|
||||
color.rgb += offset.rgb;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
color = fog_clamp(color);
|
||||
|
||||
#if pp_FogCtrl == 0
|
||||
color.rgb = lerp(color.rgb, FOG_COL_RAM.rgb, fog_mode2(inpix.uv.w));
|
||||
#endif
|
||||
#if pp_FogCtrl == 1 && pp_Offset == 1 && pp_BumpMap == 0
|
||||
color.rgb = lerp(color.rgb, FOG_COL_VERT.rgb, offset.a);
|
||||
#endif
|
||||
|
||||
#if pp_TriLinear == 1
|
||||
color *= trilinear_alpha;
|
||||
#endif
|
||||
|
||||
//color.rgb = float3(inpix.uv.w * sp_FOG_DENSITY / 128.0f);
|
||||
PSO pso;
|
||||
float w = inpix.uv.w * 100000.0f;
|
||||
pso.z = log2(1.0f + w) / 34.0f;
|
||||
pso.col = color;
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
PSO modifierVolume(float4 uv : TEXCOORD0)
|
||||
{
|
||||
PSO pso;
|
||||
float w = uv.w * 100000.0f;
|
||||
pso.z = log2(1.0f + w) / 34.0f;
|
||||
pso.col = float4(0, 0, 0, 0.5f); // TODO use sp_ShaderColor uniform
|
||||
|
||||
return pso;
|
||||
}
|
||||
)";
|
||||
|
||||
const char *MacroValues[] { "0", "1", "2", "3" };
|
||||
|
||||
static D3DXMACRO VertexMacros[]
|
||||
{
|
||||
{ "pp_Gouraud", "1" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
constexpr u32 MacroTexture = 0;
|
||||
constexpr u32 MacroOffset = 1;
|
||||
constexpr u32 MacroShadInstr = 2;
|
||||
constexpr u32 MacroIgnoreTexA = 3;
|
||||
constexpr u32 MacroUseAlpha = 4;
|
||||
constexpr u32 MacroFogCtrl = 5;
|
||||
constexpr u32 MacroFogClamping = 6;
|
||||
constexpr u32 MacroPalette = 7;
|
||||
constexpr u32 MacroBumpMap = 8;
|
||||
constexpr u32 MacroTriLinear = 9;
|
||||
constexpr u32 MacroGouraud = 10;
|
||||
|
||||
static D3DXMACRO PixelMacros[]
|
||||
{
|
||||
{ "pp_Texture", "0" },
|
||||
{ "pp_Offset", "0" },
|
||||
{ "pp_ShadInstr", "0" },
|
||||
{ "pp_IgnoreTexA", "0" },
|
||||
{ "pp_UseAlpha", "0" },
|
||||
{ "pp_FogCtrl", "0" },
|
||||
{ "FogClamping", "0" },
|
||||
{ "pp_Palette", "0" },
|
||||
{ "pp_BumpMap", "0" },
|
||||
{ "pp_TriLinear", "0" },
|
||||
{ "pp_Gouraud", "1" },
|
||||
{0, 0}
|
||||
//{ "pp_ClipInside", "0" }, // TODO
|
||||
};
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& D3DShaders::getShader(bool pp_Texture, bool pp_UseAlpha, bool pp_IgnoreTexA, u32 pp_ShadInstr,
|
||||
bool pp_Offset, u32 pp_FogCtrl, bool pp_BumpMap, bool fog_clamping,
|
||||
bool trilinear, bool palette, bool gouraud)
|
||||
{
|
||||
u32 hash = pp_Texture
|
||||
| (pp_UseAlpha << 1)
|
||||
| (pp_IgnoreTexA << 2)
|
||||
| (pp_ShadInstr << 3)
|
||||
| (pp_Offset << 5)
|
||||
| (pp_FogCtrl << 6)
|
||||
| (pp_BumpMap << 8)
|
||||
| (fog_clamping << 9)
|
||||
| (trilinear << 10)
|
||||
| (palette << 11)
|
||||
| (gouraud << 12);
|
||||
auto it = shaders.find(hash);
|
||||
if (it == shaders.end())
|
||||
{
|
||||
verify(pp_ShadInstr < ARRAY_SIZE(MacroValues));
|
||||
verify(pp_FogCtrl < ARRAY_SIZE(MacroValues));
|
||||
PixelMacros[MacroTexture].Definition = MacroValues[pp_Texture];
|
||||
PixelMacros[MacroUseAlpha].Definition = MacroValues[pp_UseAlpha];
|
||||
PixelMacros[MacroIgnoreTexA].Definition = MacroValues[pp_IgnoreTexA];
|
||||
PixelMacros[MacroShadInstr].Definition = MacroValues[pp_ShadInstr];
|
||||
PixelMacros[MacroOffset].Definition = MacroValues[pp_Offset];
|
||||
PixelMacros[MacroFogCtrl].Definition = MacroValues[pp_FogCtrl];
|
||||
PixelMacros[MacroBumpMap].Definition = MacroValues[pp_BumpMap];
|
||||
PixelMacros[MacroFogClamping].Definition = MacroValues[fog_clamping];
|
||||
PixelMacros[MacroTriLinear].Definition = MacroValues[trilinear];
|
||||
PixelMacros[MacroPalette].Definition = MacroValues[palette];
|
||||
PixelMacros[MacroGouraud].Definition = MacroValues[gouraud];
|
||||
ComPtr<IDirect3DPixelShader9> shader = compilePS(PixelShader, "main", PixelMacros);
|
||||
verify((bool )shader);
|
||||
it = shaders.insert(std::make_pair(hash, shader)).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DVertexShader9>& D3DShaders::getVertexShader(bool gouraud)
|
||||
{
|
||||
ComPtr<IDirect3DVertexShader9>& vertexShader = gouraud ? gouraudVertexShader : flatVertexShader;
|
||||
if (!vertexShader)
|
||||
{
|
||||
VertexMacros[0].Definition = MacroValues[gouraud];
|
||||
vertexShader = compileVS(VertexShader, "main", VertexMacros);
|
||||
}
|
||||
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& D3DShaders::getModVolShader()
|
||||
{
|
||||
if (!modVolShader)
|
||||
modVolShader = compilePS(PixelShader, "modifierVolume", PixelMacros);
|
||||
|
||||
return modVolShader;
|
||||
}
|
||||
|
||||
ComPtr<ID3DXBuffer> D3DShaders::compileShader(const char* source, const char* function, const char* profile, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> errors;
|
||||
ComPtr<ID3DXBuffer> shader;
|
||||
ComPtr<ID3DXConstantTable> constants;
|
||||
D3DXCompileShader(source, strlen(source), pDefines, NULL, function, profile, SHADER_DEBUG, &shader.get(), &errors.get(), &constants.get());
|
||||
if (errors) {
|
||||
char *text = (char *) errors->GetBufferPointer();
|
||||
WARN_LOG(RENDERER, "%s", text);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
ComPtr<IDirect3DVertexShader9> D3DShaders::compileVS(const char* source, const char* function, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> buffer = compileShader(source, function, D3DXGetVertexShaderProfile(device), pDefines);
|
||||
ComPtr<IDirect3DVertexShader9> shader;
|
||||
if (buffer)
|
||||
device->CreateVertexShader((DWORD *)buffer->GetBufferPointer(), &shader.get());
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
ComPtr<IDirect3DPixelShader9> D3DShaders::compilePS(const char* source, const char* function, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> buffer = compileShader(source, function, D3DXGetPixelShaderProfile(device), pDefines);
|
||||
ComPtr<IDirect3DPixelShader9> shader;
|
||||
if (buffer)
|
||||
device->CreatePixelShader((DWORD *)buffer->GetBufferPointer(), &shader.get());
|
||||
|
||||
return shader;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "dxcontext.h"
|
||||
#include <D3DX9Shader.h>
|
||||
|
||||
class D3DShaders
|
||||
{
|
||||
public:
|
||||
void init(const ComPtr<IDirect3DDevice9>& device)
|
||||
{
|
||||
this->device = device;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& getShader(bool pp_Texture, bool pp_UseAlpha, bool pp_IgnoreTexA, u32 pp_ShadInstr,
|
||||
bool pp_Offset, u32 pp_FogCtrl, bool pp_BumpMap, bool fog_clamping, bool trilinear, bool palette, bool gouraud);
|
||||
const ComPtr<IDirect3DVertexShader9>& getVertexShader(bool gouraud);
|
||||
const ComPtr<IDirect3DPixelShader9>& getModVolShader();
|
||||
|
||||
private:
|
||||
ComPtr<ID3DXBuffer> compileShader(const char* source, const char* function, const char* profile, const D3DXMACRO* pDefines);
|
||||
ComPtr<IDirect3DVertexShader9> compileVS(const char* source, const char* function, const D3DXMACRO* pDefines);
|
||||
ComPtr<IDirect3DPixelShader9> compilePS(const char* source, const char* function, const D3DXMACRO* pDefines);
|
||||
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
std::unordered_map<u32, ComPtr<IDirect3DPixelShader9>> shaders;
|
||||
ComPtr<IDirect3DVertexShader9> gouraudVertexShader;
|
||||
ComPtr<IDirect3DVertexShader9> flatVertexShader;
|
||||
ComPtr<IDirect3DPixelShader9> modVolShader;
|
||||
};
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "d3d_texture.h"
|
||||
|
||||
void D3DTexture::UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
D3DFORMAT d3dFormat;
|
||||
u32 bpp = 2;
|
||||
switch (tex_type)
|
||||
{
|
||||
case TextureType::_5551:
|
||||
d3dFormat = D3DFMT_A1R5G5B5;
|
||||
break;
|
||||
case TextureType::_4444:
|
||||
d3dFormat = D3DFMT_A4R4G4B4;
|
||||
break;
|
||||
case TextureType::_565:
|
||||
d3dFormat = D3DFMT_R5G6B5;
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
bpp = 4;
|
||||
d3dFormat = D3DFMT_A8R8G8B8;
|
||||
break;
|
||||
case TextureType::_8:
|
||||
bpp = 1;
|
||||
d3dFormat = D3DFMT_A8;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (mipmapsIncluded)
|
||||
{
|
||||
// TODO Upload all mipmap levels
|
||||
int mipmapLevels = 0;
|
||||
int dim = width;
|
||||
while (dim != 0)
|
||||
{
|
||||
mipmapLevels++;
|
||||
dim >>= 1;
|
||||
}
|
||||
for (int i = 0; i < mipmapLevels - 1; i++)
|
||||
temp_tex_buffer += (1 << (2 * i)) * bpp;
|
||||
}
|
||||
if (texture == nullptr)
|
||||
{
|
||||
if (mipmapped)
|
||||
theDXContext.getDevice()->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, d3dFormat, D3DPOOL_MANAGED, &texture.get(), 0);
|
||||
else
|
||||
theDXContext.getDevice()->CreateTexture(width, height, 1, 0, d3dFormat, D3DPOOL_MANAGED, &texture.get(), 0);
|
||||
verify(texture != nullptr);
|
||||
}
|
||||
D3DLOCKED_RECT rect;
|
||||
texture->LockRect(0, &rect, NULL, 0 /* | D3DLOCK_DISCARD*/);
|
||||
if (width * bpp == (u32)rect.Pitch)
|
||||
memcpy(rect.pBits, temp_tex_buffer, width * bpp * height);
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
for (int l = 0; l < height; l++)
|
||||
{
|
||||
memcpy(dst, temp_tex_buffer, width * bpp);
|
||||
dst += rect.Pitch;
|
||||
temp_tex_buffer += width * bpp;
|
||||
}
|
||||
}
|
||||
texture->UnlockRect(0);
|
||||
}
|
||||
|
||||
bool D3DTexture::Delete()
|
||||
{
|
||||
if (!BaseTextureCacheData::Delete())
|
||||
return false;
|
||||
|
||||
texture.reset();
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "rend/TexCache.h"
|
||||
#include <d3d9.h>
|
||||
#include "dxcontext.h"
|
||||
|
||||
class D3DTexture final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
ComPtr<IDirect3DTexture9> texture;
|
||||
std::string GetId() override { return std::to_string((uintptr_t)texture.get()); }
|
||||
void UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped,
|
||||
bool mipmapsIncluded = false) override;
|
||||
bool Delete() override;
|
||||
};
|
||||
|
||||
class D3DTextureCache final : public BaseTextureCache<D3DTexture>
|
||||
{
|
||||
public:
|
||||
D3DTextureCache() {
|
||||
D3DTexture::SetDirectXColorOrder(true); // TODO need to be reset to false by other renderers
|
||||
}
|
||||
~D3DTextureCache() {
|
||||
Clear();
|
||||
}
|
||||
void Cleanup()
|
||||
{
|
||||
texturesToDelete.clear();
|
||||
CollectCleanup();
|
||||
}
|
||||
void DeleteLater(ComPtr<IDirect3DTexture9> tex) { texturesToDelete.push_back(tex); }
|
||||
|
||||
private:
|
||||
std::vector<ComPtr<IDirect3DTexture9>> texturesToDelete;
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "dxcontext.h"
|
||||
#include "rend/gui.h"
|
||||
#include "sdl/sdl.h"
|
||||
|
||||
DXContext theDXContext;
|
||||
extern int screen_width, screen_height; // FIXME
|
||||
|
||||
bool DXContext::Init()
|
||||
{
|
||||
if (!sdl_recreate_window(0))
|
||||
return false;
|
||||
|
||||
pD3D.reset(Direct3DCreate9(D3D_SDK_VERSION));
|
||||
if (!pD3D)
|
||||
return false;
|
||||
NOTICE_LOG(RENDERER, "Direct3D object created");
|
||||
memset(&d3dpp, 0, sizeof(d3dpp));
|
||||
d3dpp.Windowed = TRUE; // FIXME
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // Need to use an explicit format with alpha if needing per-pixel alpha composition.
|
||||
d3dpp.EnableAutoDepthStencil = TRUE;
|
||||
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; // TODO D3DFMT_D24FS8 if supported?
|
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // Present with vsync
|
||||
//d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync, maximum unthrottled framerate
|
||||
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, sdl_get_native_hwnd(),
|
||||
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pDevice.get())))
|
||||
return false;
|
||||
gui_init();
|
||||
return ImGui_ImplDX9_Init(pDevice.get());
|
||||
}
|
||||
|
||||
void DXContext::Term()
|
||||
{
|
||||
ImGui_ImplDX9_Shutdown();
|
||||
pDevice.reset();
|
||||
pD3D.reset();
|
||||
}
|
||||
|
||||
void DXContext::Present()
|
||||
{
|
||||
HRESULT result = pDevice->Present(NULL, NULL, NULL, NULL);
|
||||
// Handle loss of D3D9 device
|
||||
if (result == D3DERR_DEVICELOST && pDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
|
||||
resetDevice();
|
||||
}
|
||||
|
||||
void DXContext::EndImGuiFrame()
|
||||
{
|
||||
verify((bool)pDevice);
|
||||
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
if (!overlay)
|
||||
{
|
||||
pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0);
|
||||
if (renderer != nullptr)
|
||||
renderer->RenderLastFrame();
|
||||
}
|
||||
if (SUCCEEDED(pDevice->BeginScene()))
|
||||
{
|
||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
||||
pDevice->EndScene();
|
||||
}
|
||||
}
|
||||
|
||||
void DXContext::resize()
|
||||
{
|
||||
if (!pDevice)
|
||||
return;
|
||||
RECT rect;
|
||||
GetClientRect(sdl_get_native_hwnd(), &rect);
|
||||
d3dpp.BackBufferWidth = screen_width = rect.right;
|
||||
d3dpp.BackBufferHeight = screen_height = rect.bottom;
|
||||
resetDevice();
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include "imgui_impl_dx9.h"
|
||||
#include "types.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
template<typename T>
|
||||
class ComPtr
|
||||
{
|
||||
public:
|
||||
ComPtr() = default;
|
||||
ComPtr(const ComPtr& other) : ptr(other.ptr) {
|
||||
if (ptr != nullptr)
|
||||
ptr->AddRef();
|
||||
}
|
||||
ComPtr(ComPtr&& other) noexcept {
|
||||
std::swap(ptr, other.ptr);
|
||||
}
|
||||
~ComPtr() {
|
||||
if (ptr != nullptr)
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
ComPtr& operator=(const ComPtr& other) {
|
||||
if (this != &other)
|
||||
*this = ComPtr(other);
|
||||
return *this;
|
||||
}
|
||||
ComPtr& operator=(ComPtr&& other) noexcept {
|
||||
std::swap(ptr, other.ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* operator->() const noexcept {
|
||||
return ptr;
|
||||
}
|
||||
explicit operator bool() const noexcept {
|
||||
return ptr != nullptr;
|
||||
}
|
||||
operator T*() const noexcept {
|
||||
return ptr;
|
||||
}
|
||||
T*& get() noexcept {
|
||||
return ptr;
|
||||
}
|
||||
void reset(T *ptr = nullptr) {
|
||||
if (ptr == this->ptr)
|
||||
return;
|
||||
std::swap(this->ptr, ptr);
|
||||
if (ptr != nullptr)
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
private:
|
||||
T *ptr = nullptr;
|
||||
};
|
||||
|
||||
class DXContext
|
||||
{
|
||||
public:
|
||||
bool Init();
|
||||
void Term();
|
||||
void EndImGuiFrame();
|
||||
void Present();
|
||||
const ComPtr<IDirect3D9>& getD3D() const { return pD3D; }
|
||||
const ComPtr<IDirect3DDevice9>& getDevice() const { return pDevice; }
|
||||
void resize();
|
||||
void setOverlay(bool overlay) { this->overlay = overlay; }
|
||||
std::string getDriverName() const {
|
||||
D3DADAPTER_IDENTIFIER9 id;
|
||||
pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id);
|
||||
return std::string(id.Description);
|
||||
}
|
||||
std::string getDriverVersion() const {
|
||||
D3DADAPTER_IDENTIFIER9 id;
|
||||
pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id);
|
||||
return std::to_string(id.DriverVersion.HighPart >> 16) + "." + std::to_string((u16)id.DriverVersion.HighPart)
|
||||
+ "." + std::to_string(id.DriverVersion.LowPart >> 16) + "." + std::to_string((u16)id.DriverVersion.LowPart);
|
||||
}
|
||||
|
||||
private:
|
||||
void resetDevice()
|
||||
{
|
||||
rend_term_renderer();
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
HRESULT hr = pDevice->Reset(&d3dpp);
|
||||
if (hr == D3DERR_INVALIDCALL)
|
||||
die("DX9 device reset failed");
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
rend_init_renderer();
|
||||
}
|
||||
|
||||
ComPtr<IDirect3D9> pD3D;
|
||||
ComPtr<IDirect3DDevice9> pDevice;
|
||||
D3DPRESENT_PARAMETERS d3dpp;
|
||||
bool overlay;
|
||||
};
|
||||
extern DXContext theDXContext;
|
||||
#endif
|
|
@ -0,0 +1,290 @@
|
|||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui_impl_dx9.h"
|
||||
|
||||
// DirectX
|
||||
#include <d3d9.h>
|
||||
|
||||
// DirectX data
|
||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||
|
||||
struct CUSTOMVERTEX
|
||||
{
|
||||
float pos[3];
|
||||
D3DCOLOR col;
|
||||
float uv[2];
|
||||
};
|
||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||
|
||||
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||
{
|
||||
// Setup viewport
|
||||
D3DVIEWPORT9 vp;
|
||||
vp.X = vp.Y = 0;
|
||||
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
g_pd3dDevice->SetViewport(&vp);
|
||||
|
||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
||||
g_pd3dDevice->SetPixelShader(NULL);
|
||||
g_pd3dDevice->SetVertexShader(NULL);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||
{
|
||||
float L = draw_data->DisplayPos.x + 0.5f;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||
float T = draw_data->DisplayPos.y + 0.5f;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
D3DMATRIX mat_projection =
|
||||
{ { {
|
||||
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||
} } };
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||
}
|
||||
}
|
||||
|
||||
// Render function.
|
||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Create and grow buffers if needed
|
||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup the DX9 state
|
||||
IDirect3DStateBlock9* d3d9_state_block = NULL;
|
||||
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
||||
return;
|
||||
|
||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||
D3DMATRIX last_world, last_view, last_projection;
|
||||
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
||||
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
||||
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||
CUSTOMVERTEX* vtx_dst;
|
||||
ImDrawIdx* idx_dst;
|
||||
if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
|
||||
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
|
||||
{
|
||||
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||
vtx_dst->pos[2] = 0.0f;
|
||||
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
vtx_dst->col = vtx_src->col;
|
||||
#else
|
||||
vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000) >> 16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9
|
||||
#endif
|
||||
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||
vtx_dst++;
|
||||
vtx_src++;
|
||||
}
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
g_pVB->Unlock();
|
||||
g_pIB->Unlock();
|
||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
|
||||
g_pd3dDevice->SetIndices(g_pIB);
|
||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->TextureId;
|
||||
g_pd3dDevice->SetTexture(0, texture);
|
||||
g_pd3dDevice->SetScissorRect(&r);
|
||||
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// Restore the DX9 transform
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// Restore the DX9 state
|
||||
d3d9_state_block->Apply();
|
||||
d3d9_state_block->Release();
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||
{
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_dx9";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
g_pd3dDevice = device;
|
||||
g_pd3dDevice->AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||
}
|
||||
|
||||
static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height, bytes_per_pixel;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||
|
||||
// Upload texture to graphics system
|
||||
g_FontTexture = NULL;
|
||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
||||
return false;
|
||||
D3DLOCKED_RECT tex_locked_rect;
|
||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||
return false;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
||||
g_FontTexture->UnlockRect(0);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return false;
|
||||
if (!ImGui_ImplDX9_CreateFontsTexture())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return;
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame()
|
||||
{
|
||||
if (!g_FontTexture)
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui/imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct IDirect3DDevice9;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
|
@ -589,6 +589,8 @@ static bool gl4_init()
|
|||
UpscalexBRZ(2, src, dst, 2, 2, false);
|
||||
}
|
||||
fog_needs_update = true;
|
||||
palette_updated = true;
|
||||
TextureCacheData::SetDirectXColorOrder(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -158,11 +158,13 @@ __forceinline
|
|||
else
|
||||
SetBaseClipping();
|
||||
|
||||
//This bit control which pixels are affected
|
||||
//by modvols
|
||||
const u32 stencil=(gp->pcw.Shadow!=0)?0x80:0x0;
|
||||
|
||||
glcache.StencilFunc(GL_ALWAYS,stencil,stencil);
|
||||
if (config::ModifierVolumes)
|
||||
{
|
||||
//This bit control which pixels are affected
|
||||
//by modvols
|
||||
const u32 stencil = gp->pcw.Shadow != 0 ? 0x80 : 0;
|
||||
glcache.StencilFunc(GL_ALWAYS, stencil, stencil);
|
||||
}
|
||||
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gp->texid == (u64)-1 ? 0 : (GLuint)gp->texid);
|
||||
|
||||
|
|
|
@ -853,6 +853,8 @@ bool gles_init()
|
|||
UpscalexBRZ(2, src, dst, 2, 2, false);
|
||||
}
|
||||
fog_needs_update = true;
|
||||
palette_updated = true;
|
||||
TextureCacheData::SetDirectXColorOrder(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -246,6 +246,10 @@ static void ImGui_Impl_NewFrame()
|
|||
{
|
||||
if (config::RendererType.isOpenGL())
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
ImGui_ImplDX9_NewFrame();
|
||||
#endif
|
||||
ImGui::GetIO().DisplaySize.x = screen_width;
|
||||
ImGui::GetIO().DisplaySize.y = screen_height;
|
||||
|
||||
|
@ -856,8 +860,6 @@ static void gui_display_settings()
|
|||
{
|
||||
static bool maple_devices_changed;
|
||||
|
||||
RenderType pvr_rend = config::RendererType;
|
||||
bool vulkan = !config::RendererType.isOpenGL();
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
|
||||
|
@ -1175,10 +1177,37 @@ static void gui_display_settings()
|
|||
}
|
||||
if (ImGui::BeginTabItem("Video"))
|
||||
{
|
||||
int renderApi;
|
||||
bool perPixel;
|
||||
switch (config::RendererType)
|
||||
{
|
||||
default:
|
||||
case RenderType::OpenGL:
|
||||
renderApi = 0;
|
||||
perPixel = false;
|
||||
break;
|
||||
case RenderType::OpenGL_OIT:
|
||||
renderApi = 0;
|
||||
perPixel = true;
|
||||
break;
|
||||
case RenderType::Vulkan:
|
||||
renderApi = 1;
|
||||
perPixel = false;
|
||||
break;
|
||||
case RenderType::Vulkan_OIT:
|
||||
renderApi = 1;
|
||||
perPixel = true;
|
||||
break;
|
||||
case RenderType::DirectX9:
|
||||
renderApi = 2;
|
||||
perPixel = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
|
||||
#if !defined(__APPLE__)
|
||||
bool has_per_pixel = false;
|
||||
if (!vulkan)
|
||||
if (renderApi == 0)
|
||||
has_per_pixel = !theGLContext.IsGLES() && theGLContext.GetMajorVersion() >= 4;
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
|
@ -1189,7 +1218,7 @@ static void gui_display_settings()
|
|||
#endif
|
||||
if (ImGui::CollapsingHeader("Transparent Sorting", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
int renderer = (pvr_rend == RenderType::OpenGL_OIT || pvr_rend == RenderType::Vulkan_OIT) ? 2 : config::PerStripSorting ? 1 : 0;
|
||||
int renderer = perPixel ? 2 : config::PerStripSorting ? 1 : 0;
|
||||
ImGui::Columns(has_per_pixel ? 3 : 2, "renderers", false);
|
||||
ImGui::RadioButton("Per Triangle", &renderer, 0);
|
||||
ImGui::SameLine();
|
||||
|
@ -1209,24 +1238,15 @@ static void gui_display_settings()
|
|||
switch (renderer)
|
||||
{
|
||||
case 0:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL; // regular Open GL
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan; // regular Vulkan
|
||||
perPixel = false;
|
||||
config::PerStripSorting.set(false);
|
||||
break;
|
||||
case 1:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL;
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan;
|
||||
perPixel = false;
|
||||
config::PerStripSorting.set(true);
|
||||
break;
|
||||
case 2:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL_OIT;
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan_OIT;
|
||||
perPixel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1253,11 +1273,27 @@ static void gui_display_settings()
|
|||
OptionCheckbox("Rotate Screen 90°", config::Rotate90, "Rotate the screen 90° counterclockwise");
|
||||
OptionCheckbox("Delay Frame Swapping", config::DelayFrameSwapping,
|
||||
"Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms");
|
||||
#ifdef USE_VULKAN
|
||||
ImGui::Checkbox("Use Vulkan Renderer", &vulkan);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Use Vulkan instead of Open GL/GLES");
|
||||
#if defined(USE_VULKAN) || defined(_WIN32)
|
||||
ImGui::Text("Graphics API:");
|
||||
#if defined(USE_VULKAN) && defined(_WIN32)
|
||||
constexpr u32 columns = 3;
|
||||
#else
|
||||
constexpr u32 columns = 2;
|
||||
#endif
|
||||
ImGui::Columns(columns, "renderApi", false);
|
||||
ImGui::RadioButton("Open GL", &renderApi, 0);
|
||||
ImGui::NextColumn();
|
||||
#ifdef USE_VULKAN
|
||||
ImGui::RadioButton("Vulkan", &renderApi, 1);
|
||||
ImGui::NextColumn();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
ImGui::RadioButton("DirectX", &renderApi, 2);
|
||||
ImGui::NextColumn();
|
||||
#endif
|
||||
ImGui::Columns(1, NULL, false);
|
||||
#endif
|
||||
|
||||
const std::array<float, 9> scalings{ 0.5f, 1.f, 1.5f, 2.f, 2.5f, 3.f, 4.f, 4.5f, 5.f };
|
||||
const std::array<std::string, 9> scalingsText{ "Half", "Native", "x1.5", "x2", "x2.5", "x3", "x4", "x4.5", "x5" };
|
||||
std::array<int, scalings.size()> vres;
|
||||
|
@ -1337,6 +1373,19 @@ static void gui_display_settings()
|
|||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndTabItem();
|
||||
|
||||
switch (renderApi)
|
||||
{
|
||||
case 0:
|
||||
config::RendererType = perPixel ? RenderType::OpenGL_OIT : RenderType::OpenGL;
|
||||
break;
|
||||
case 1:
|
||||
config::RendererType = perPixel ? RenderType::Vulkan_OIT : RenderType::Vulkan;
|
||||
break;
|
||||
case 2:
|
||||
config::RendererType = RenderType::DirectX9;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginTabItem("Audio"))
|
||||
{
|
||||
|
@ -1569,7 +1618,7 @@ static void gui_display_settings()
|
|||
}
|
||||
}
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
else if (config::RendererType.isVulkan())
|
||||
{
|
||||
if (ImGui::CollapsingHeader("Vulkan", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
|
@ -1580,6 +1629,18 @@ static void gui_display_settings()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
{
|
||||
if (ImGui::CollapsingHeader("DirectX", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
std::string name = theDXContext.getDriverName();
|
||||
ImGui::Text("Driver Name: %s", name.c_str());
|
||||
std::string version = theDXContext.getDriverVersion();
|
||||
ImGui::Text("Version: %s", version.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
ImGui::Separator();
|
||||
|
@ -1599,11 +1660,6 @@ static void gui_display_settings()
|
|||
ScrollWhenDraggingOnVoid(ImVec2(0.0f, -mouse_delta.y), ImGuiMouseButton_Left);
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (vulkan != !config::RendererType.isOpenGL())
|
||||
pvr_rend = !vulkan ? RenderType::OpenGL
|
||||
: config::RendererType == RenderType::OpenGL_OIT ? RenderType::Vulkan_OIT : RenderType::Vulkan;
|
||||
config::RendererType = pvr_rend;
|
||||
}
|
||||
|
||||
void gui_display_notification(const char *msg, int duration)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "imgui/imgui_internal.h"
|
||||
#include "gles/imgui_impl_opengl3.h"
|
||||
#include "vulkan/vulkan_context.h"
|
||||
#include "dx9/dxcontext.h"
|
||||
#include "gui.h"
|
||||
|
||||
extern int screen_width, screen_height;
|
||||
|
@ -37,9 +38,14 @@ void select_file_popup(const char *prompt, StringCallback callback,
|
|||
static inline void ImGui_impl_RenderDrawData(ImDrawData *draw_data)
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
if (!config::RendererType.isOpenGL())
|
||||
if (config::RendererType.isVulkan())
|
||||
ImGui_ImplVulkan_RenderDrawData(draw_data);
|
||||
else
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (config::RendererType.isDirectX())
|
||||
theDXContext.EndImGuiFrame();
|
||||
else
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_RenderDrawData(draw_data);
|
||||
}
|
||||
|
|
|
@ -78,18 +78,23 @@ void mainui_loop()
|
|||
if (config::RendererType.isOpenGL())
|
||||
theGLContext.Swap();
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
else if (config::RendererType.isVulkan())
|
||||
VulkanContext::Instance()->Present();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
theDXContext.Present();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (config::RendererType.pendingChange() || forceReinit)
|
||||
{
|
||||
bool openGl = config::RendererType.isOpenGL();
|
||||
int api = config::RendererType.isOpenGL() ? 0 : config::RendererType.isVulkan() ? 1 : 2;
|
||||
mainui_term();
|
||||
config::RendererType.commit();
|
||||
if (openGl != config::RendererType.isOpenGL() || forceReinit)
|
||||
// Switch between vulkan and opengl (or full reinit)
|
||||
int newApi = config::RendererType.isOpenGL() ? 0 : config::RendererType.isVulkan() ? 1 : 2;
|
||||
if (newApi != api || forceReinit)
|
||||
// Switch between vulkan/opengl/directx (or full reinit)
|
||||
SwitchRenderApi();
|
||||
mainui_init();
|
||||
forceReinit = false;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
extern int screen_width, screen_height;
|
||||
|
||||
template<bool invertY>
|
||||
template<bool invertYForScreen, bool invertYForRTT = false>
|
||||
class TransformMatrix
|
||||
{
|
||||
public:
|
||||
|
@ -77,8 +77,8 @@ public:
|
|||
{
|
||||
dcViewport.x = renderingContext->fb_X_CLIP.max - renderingContext->fb_X_CLIP.min + 1;
|
||||
dcViewport.y = renderingContext->fb_Y_CLIP.max - renderingContext->fb_Y_CLIP.min + 1;
|
||||
normalMatrix = glm::translate(glm::vec3(-1, -1, 0))
|
||||
* glm::scale(glm::vec3(2.0f / dcViewport.x, 2.0f / dcViewport.y, 1.f));
|
||||
normalMatrix = glm::translate(glm::vec3(-1, invertYForRTT ? 1 : -1, 0))
|
||||
* glm::scale(glm::vec3(2.0f / dcViewport.x, 2.0f / dcViewport.y * (invertYForRTT ? -1 : 1), 1.f));
|
||||
scissorMatrix = normalMatrix;
|
||||
sidebarWidth = 0;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public:
|
|||
float dc2s_scale_h = renderViewport.x / 640.0f;
|
||||
|
||||
sidebarWidth = 0;
|
||||
y_coef = 2.0f / (renderViewport.y / dc2s_scale_h * scale_y) * screen_stretching * (invertY ? -1 : 1);
|
||||
y_coef = 2.0f / (renderViewport.y / dc2s_scale_h * scale_y) * screen_stretching * (invertYForScreen ? -1 : 1);
|
||||
x_coef = 2.0f / dcViewport.x;
|
||||
}
|
||||
else
|
||||
|
@ -151,9 +151,9 @@ public:
|
|||
|
||||
sidebarWidth = (renderViewport.x - dc2s_scale_h * 640.0f * screen_stretching) / 2;
|
||||
x_coef = 2.0f / (renderViewport.x / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
y_coef = 2.0f / dcViewport.y * (invertY ? -1 : 1);
|
||||
y_coef = 2.0f / dcViewport.y * (invertYForScreen ? -1 : 1);
|
||||
}
|
||||
trans_rot = glm::translate(glm::vec3(-1 + 2 * sidebarWidth / renderViewport.x, invertY ? 1 : -1, 0));
|
||||
trans_rot = glm::translate(glm::vec3(-1 + 2 * sidebarWidth / renderViewport.x, invertYForScreen ? 1 : -1, 0));
|
||||
|
||||
normalMatrix = trans_rot
|
||||
* glm::scale(glm::vec3(x_coef, y_coef, 1.f))
|
||||
|
|
|
@ -137,6 +137,9 @@ private:
|
|||
class TextureCache final : public BaseTextureCache<Texture>
|
||||
{
|
||||
public:
|
||||
TextureCache() {
|
||||
Texture::SetDirectXColorOrder(false);
|
||||
}
|
||||
void SetCurrentIndex(int index) {
|
||||
if (currentIndex < inFlightTextures.size())
|
||||
std::for_each(inFlightTextures[currentIndex].begin(), inFlightTextures[currentIndex].end(),
|
||||
|
|
|
@ -303,17 +303,20 @@ void input_sdl_handle()
|
|||
for (int i = 0; event.text.text[i] != '\0'; i++)
|
||||
sdl_keyboard->keyboard_character(event.text.text[i]);
|
||||
break;
|
||||
#ifdef USE_VULKAN
|
||||
case SDL_WINDOWEVENT:
|
||||
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
|
||||
|| event.window.event == SDL_WINDOWEVENT_RESTORED
|
||||
|| event.window.event == SDL_WINDOWEVENT_MINIMIZED
|
||||
|| event.window.event == SDL_WINDOWEVENT_MAXIMIZED)
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.SetResized();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
theDXContext.resize();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
|
@ -474,7 +477,6 @@ bool sdl_recreate_window(u32 flags)
|
|||
get_window_state();
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
flags |= SDL_SWSURFACE;
|
||||
#if !defined(GLES)
|
||||
flags |= SDL_WINDOW_RESIZABLE;
|
||||
if (window_fullscreen)
|
||||
|
@ -491,6 +493,8 @@ bool sdl_recreate_window(u32 flags)
|
|||
ERROR_LOG(COMMON, "Window creation failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
screen_width = window_width * scaling;
|
||||
screen_height = window_height * scaling;
|
||||
|
||||
#if !defined(GLES) && !defined(_WIN32)
|
||||
// Set the window icon
|
||||
|
|
|
@ -294,7 +294,8 @@ enum class RenderType {
|
|||
OpenGL = 0,
|
||||
OpenGL_OIT = 3,
|
||||
Vulkan = 4,
|
||||
Vulkan_OIT = 5
|
||||
Vulkan_OIT = 5,
|
||||
DirectX9 = 1,
|
||||
};
|
||||
|
||||
enum class KeyboardLayout {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include "gl_context.h"
|
||||
#include "rend/dx9/dxcontext.h"
|
||||
#ifdef USE_VULKAN
|
||||
#include "rend/vulkan/vulkan_context.h"
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ VulkanContext theVulkanContext;
|
|||
void InitRenderApi()
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
if (!config::RendererType.isOpenGL())
|
||||
if (config::RendererType.isVulkan())
|
||||
{
|
||||
if (theVulkanContext.Init())
|
||||
return;
|
||||
|
@ -38,6 +38,17 @@ void InitRenderApi()
|
|||
config::RendererType = RenderType::OpenGL;
|
||||
config::RendererType.commit();
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (config::RendererType.isDirectX())
|
||||
{
|
||||
if (theDXContext.Init())
|
||||
return;
|
||||
// Fall back to Open GL
|
||||
WARN_LOG(RENDERER, "DirectX init failed. Falling back to Open GL.");
|
||||
config::RendererType = RenderType::OpenGL;
|
||||
config::RendererType.commit();
|
||||
}
|
||||
#endif
|
||||
if (!theGLContext.Init())
|
||||
exit(1);
|
||||
|
@ -47,6 +58,9 @@ void TermRenderApi()
|
|||
{
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.Term();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
theDXContext.Term();
|
||||
#endif
|
||||
theGLContext.Term();
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ else ifneq (,$(findstring win32,$(platform)))
|
|||
NOT_ARM := 1
|
||||
CFLAGS += -fno-builtin-sqrtf -funroll-loops -I /mingw64/include
|
||||
LDFLAGS += -static-libgcc -static-libstdc++ -Wl,-subsystem,windows
|
||||
LIBS := -lopengl32 -lwinmm -lgdi32 -lwsock32 -lws2_32 -ldsound -lcomctl32 -lcomdlg32 -lxinput -liphlpapi -Wl,-Bstatic -lgomp
|
||||
LIBS := -lopengl32 -lwinmm -lgdi32 -lwsock32 -lws2_32 -ldsound -lcomctl32 -lcomdlg32 -lxinput -liphlpapi -ld3d9 -ld3dx9 -Wl,-Bstatic -lgomp
|
||||
PLATFORM_EXT := exe
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
@ -506,7 +506,7 @@ SDL/lib/libSDL2.a:
|
|||
|
||||
OBJECTS += SDL/lib/libSDL2.a
|
||||
LIBS += -ldinput8 -ldxguid -ldxerr8
|
||||
LIBS += -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid
|
||||
LIBS += -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue