WIP directx9 renderer

This commit is contained in:
flyinghead 2021-04-12 22:49:04 +02:00
parent 4a8ce39bfd
commit f107d380b9
31 changed files with 2996 additions and 599 deletions

View File

@ -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.*)")

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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();
}

119
core/rend/dx9/dxcontext.h Normal file
View File

@ -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

View File

@ -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();
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -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))

View File

@ -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(),

View File

@ -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

View File

@ -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 {

View File

@ -20,6 +20,7 @@
*/
#pragma once
#include "gl_context.h"
#include "rend/dx9/dxcontext.h"
#ifdef USE_VULKAN
#include "rend/vulkan/vulkan_context.h"

View File

@ -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();
}

View File

@ -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