dx9: mipmaps. load/dump textures. vmu/crosshair display.
upload all texture mipmaps to gpu dump textures. load custom textures vmu and lightgun xhair display fix dx9 half-pixel offset fix 565_32 unpacker bug
This commit is contained in:
parent
c889bfa6d4
commit
abc8b18b78
|
@ -867,6 +867,9 @@ endif()
|
|||
|
||||
if(WIN32)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/dx9/comptr.h
|
||||
core/rend/dx9/d3d_overlay.h
|
||||
core/rend/dx9/d3d_overlay.cpp
|
||||
core/rend/dx9/d3d_renderer.h
|
||||
core/rend/dx9/d3d_renderer.cpp
|
||||
core/rend/dx9/d3d_shaders.h
|
||||
|
|
|
@ -182,50 +182,90 @@ void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, voi
|
|||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
switch (textype)
|
||||
if (!config::RendererType.isDirectX())
|
||||
{
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
switch (textype)
|
||||
{
|
||||
*dst++ = ((*src >> 12) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 8) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 4) & 0xF) << 4;
|
||||
*dst++ = (*src & 0xF) << 4;
|
||||
src++;
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 12) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 8) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 4) & 0xF) << 4;
|
||||
*dst++ = (*src & 0xF) << 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker565_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 6) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 1) & 0x1F) << 3;
|
||||
*dst++ = (*src & 1) ? 255 : 0;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
memcpy(dst, src, w * 4);
|
||||
dst += w * 4;
|
||||
src += w * 2;
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (textype)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 5) & 0x3F) << 2;
|
||||
*dst++ = (*src & 0x1F) << 3;
|
||||
*dst++ = 255;
|
||||
src++;
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker4444_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker565_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker1555_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = UnpackerRGBA8888_32<RGBAPacker>::unpack(*(u32 *)src);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 6) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 1) & 0x1F) << 3;
|
||||
*dst++ = (*src & 1) ? 255 : 0;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = *(u32 *)src;
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ struct Unpacker565_32 {
|
|||
return Packer::pack(
|
||||
(((word >> 11) & 0x1F) << 3) | ((word >> 13) & 7),
|
||||
(((word >> 5) & 0x3F) << 2) | ((word >> 9) & 3),
|
||||
(((word >> 0) & 0x1F) << 13) | ((word >> 2) & 7),
|
||||
(((word >> 0) & 0x1F) << 3) | ((word >> 2) & 7),
|
||||
0xFF);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
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 <utility>
|
||||
|
||||
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;
|
||||
};
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
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_overlay.h"
|
||||
#include "rend/gui.h"
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
void D3DOverlay::drawQuad(const RECT& rect, D3DCOLOR color)
|
||||
{
|
||||
device->SetTextureStageState(0, D3DTSS_CONSTANT, color);
|
||||
Vertex quad[] {
|
||||
{ (float)(rect.left), (float)(rect.top), 0.5f, 0.f, 0.f },
|
||||
{ (float)(rect.left), (float)(rect.bottom), 0.5f, 0.f, 1.f },
|
||||
{ (float)(rect.right), (float)(rect.top), 0.5f, 1.f, 0.f },
|
||||
{ (float)(rect.right), (float)(rect.bottom), 0.5f, 1.f, 1.f }
|
||||
};
|
||||
device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
|
||||
}
|
||||
|
||||
void D3DOverlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
|
||||
{
|
||||
setupRenderState(width, height);
|
||||
if (vmu)
|
||||
{
|
||||
float vmu_padding = 8.f * scaling;
|
||||
float vmu_height = 70.f * scaling;
|
||||
float vmu_width = 48.f / 32.f * vmu_height;
|
||||
|
||||
for (size_t i = 0; i < vmuTextures.size(); i++)
|
||||
{
|
||||
ComPtr < IDirect3DTexture9 > &texture = vmuTextures[i];
|
||||
if (!vmu_lcd_status[i])
|
||||
{
|
||||
texture.reset();
|
||||
continue;
|
||||
}
|
||||
if (texture == nullptr || vmu_lcd_changed[i])
|
||||
{
|
||||
device->CreateTexture(48, 32, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture.get(), 0);
|
||||
D3DLOCKED_RECT rect;
|
||||
if (SUCCEEDED(texture->LockRect(0, &rect, nullptr, 0)))
|
||||
{
|
||||
u8 *dst = (u8 *) rect.pBits;
|
||||
for (int y = 0; y < 32; y++)
|
||||
memcpy(dst + y * rect.Pitch, vmu_lcd_data[i] + (31 - y) * 48, 48 * 4);
|
||||
texture->UnlockRect(0);
|
||||
}
|
||||
vmu_lcd_changed[i] = false;
|
||||
}
|
||||
float x;
|
||||
if (i & 2)
|
||||
x = width - vmu_padding - vmu_width;
|
||||
else
|
||||
x = vmu_padding;
|
||||
float y;
|
||||
if (i & 4)
|
||||
{
|
||||
y = height - vmu_padding - vmu_height;
|
||||
if (i & 1)
|
||||
y -= vmu_padding + vmu_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = vmu_padding;
|
||||
if (i & 1)
|
||||
y += vmu_padding + vmu_height;
|
||||
}
|
||||
device->SetTexture(0, texture);
|
||||
RECT rect { (long)x, (long)y, (long)(x + vmu_width), (long)(y + vmu_height) };
|
||||
drawQuad(rect, D3DCOLOR_ARGB(192, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
if (crosshair)
|
||||
{
|
||||
if (!xhairTexture)
|
||||
{
|
||||
const u32* texData = getCrosshairTextureData();
|
||||
device->CreateTexture(16, 16, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &xhairTexture.get(), 0);
|
||||
D3DLOCKED_RECT rect;
|
||||
if (SUCCEEDED(xhairTexture->LockRect(0, &rect, nullptr, 0)))
|
||||
{
|
||||
if (rect.Pitch == 16 * sizeof(u32))
|
||||
memcpy(rect.pBits, texData, 16 * 16 * sizeof(u32));
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *) rect.pBits;
|
||||
for (int y = 0; y < 16; y++)
|
||||
memcpy(dst + y * rect.Pitch, texData + y * 16, 16 * sizeof(u32));
|
||||
}
|
||||
xhairTexture->UnlockRect(0);
|
||||
}
|
||||
}
|
||||
device->SetTexture(0, xhairTexture);
|
||||
for (u32 i = 0; i < config::CrosshairColor.size(); i++)
|
||||
{
|
||||
if (config::CrosshairColor[i] == 0)
|
||||
continue;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST
|
||||
&& config::MapleMainDevices[i] != MDT_LightGun)
|
||||
continue;
|
||||
|
||||
float x, y;
|
||||
std::tie(x, y) = getCrosshairPosition(i);
|
||||
float halfWidth = XHAIR_WIDTH / 2.f;
|
||||
RECT rect { (long) (x - halfWidth), (long) (y - halfWidth), (long) (x + halfWidth), (long) (y + halfWidth) };
|
||||
D3DCOLOR color = (config::CrosshairColor[i] & 0xFF00FF00)
|
||||
| ((config::CrosshairColor[i] >> 16) & 0xFF)
|
||||
| ((config::CrosshairColor[i] & 0xFF) << 16);
|
||||
drawQuad(rect, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3DOverlay::setupRenderState(u32 displayWidth, u32 displayHeight)
|
||||
{
|
||||
device->SetPixelShader(NULL);
|
||||
device->SetVertexShader(NULL);
|
||||
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
device->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CONSTANT);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CONSTANT);
|
||||
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
||||
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
||||
|
||||
glm::mat4 identity = glm::identity<glm::mat4>();
|
||||
glm::mat4 projection = glm::translate(glm::vec3(-1.f - 1.f / displayWidth, 1.f + 1.f / displayHeight, 0))
|
||||
* glm::scale(glm::vec3(2.f / displayWidth, -2.f / displayHeight, 1.f));
|
||||
|
||||
device->SetTransform(D3DTS_WORLD, (const D3DMATRIX *)&identity[0][0]);
|
||||
device->SetTransform(D3DTS_VIEW, (const D3DMATRIX *)&identity[0][0]);
|
||||
device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)&projection[0][0]);
|
||||
|
||||
device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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 <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include <array>
|
||||
#include "comptr.h"
|
||||
|
||||
class D3DOverlay
|
||||
{
|
||||
public:
|
||||
void init(const ComPtr<IDirect3DDevice9>& device) {
|
||||
this->device = device;
|
||||
}
|
||||
|
||||
void term() {
|
||||
device.reset();
|
||||
xhairTexture.reset();
|
||||
for (auto& vmu : vmuTextures)
|
||||
vmu.reset();
|
||||
}
|
||||
|
||||
void draw(u32 width, u32 height, bool vmu, bool crosshair);
|
||||
|
||||
private:
|
||||
void setupRenderState(u32 displayWidth, u32 displayHeight);
|
||||
void drawQuad(const RECT& rect, D3DCOLOR color);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float pos[3];
|
||||
float uv[2];
|
||||
};
|
||||
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
ComPtr<IDirect3DTexture9> xhairTexture;
|
||||
std::array<ComPtr<IDirect3DTexture9>, 8> vmuTextures;
|
||||
};
|
|
@ -225,7 +225,7 @@ u64 D3DRenderer::GetTexture(TSP tsp, TCW tcw)
|
|||
{
|
||||
texCache.DeleteLater(tf->texture);
|
||||
tf->texture.reset();
|
||||
tf->CheckCustomTexture();
|
||||
tf->loadCustomTexture();
|
||||
}
|
||||
}
|
||||
return (uintptr_t)tf->texture.get();
|
||||
|
@ -250,7 +250,14 @@ void D3DRenderer::readDCFramebuffer()
|
|||
|
||||
D3DLOCKED_RECT rect;
|
||||
dcfbTexture->LockRect(0, &rect, nullptr, 0);
|
||||
memcpy(rect.pBits, pb.data(), width * height * 4);
|
||||
if ((u32)rect.Pitch == width * sizeof(u32))
|
||||
memcpy(rect.pBits, pb.data(), width * height * sizeof(u32));
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy(dst + y * rect.Pitch, pb.data() + y * width, width * sizeof(u32));
|
||||
}
|
||||
dcfbTexture->UnlockRect(0);
|
||||
}
|
||||
|
||||
|
@ -303,7 +310,7 @@ void D3DRenderer::setGPState(const PolyParam *gp)
|
|||
float trilinear_alpha;
|
||||
if (gp->pcw.Texture && gp->tsp.FilterMode > 1 && Type != ListType_Punch_Through && gp->tcw.MipMapped == 1)
|
||||
{
|
||||
trilinear_alpha = 0.25 * (gp->tsp.MipMapD & 0x3);
|
||||
trilinear_alpha = 0.25f * (gp->tsp.MipMapD & 0x3);
|
||||
if (gp->tsp.FilterMode == 2)
|
||||
// Trilinear pass A
|
||||
trilinear_alpha = 1.f - trilinear_alpha;
|
||||
|
@ -340,15 +347,13 @@ void D3DRenderer::setGPState(const PolyParam *gp)
|
|||
{
|
||||
float paletteIndex[4];
|
||||
if (gp->tcw.PixelFmt == PixelPal4)
|
||||
paletteIndex[0] = gp->tcw.PalSelect << 4;
|
||||
paletteIndex[0] = (float)(gp->tcw.PalSelect << 4);
|
||||
else
|
||||
paletteIndex[0] = (gp->tcw.PalSelect >> 4) << 8;
|
||||
paletteIndex[0] = (float)((gp->tcw.PalSelect >> 4) << 8);
|
||||
device->SetPixelShaderConstantF(0, paletteIndex, 1);
|
||||
}
|
||||
devCache.SetVertexShader(shaders.getVertexShader(gp->pcw.Gouraud));
|
||||
devCache.SetRenderState(D3DRS_SHADEMODE, gp->pcw.Gouraud == 1 ? D3DSHADE_GOURAUD : D3DSHADE_FLAT);
|
||||
devCache.SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
|
||||
devCache.SetRenderState(D3DRS_CLIPPING, FALSE);
|
||||
|
||||
/* TODO
|
||||
if (clipmode == TileClipping::Inside)
|
||||
|
@ -395,7 +400,7 @@ void D3DRenderer::setGPState(const PolyParam *gp)
|
|||
//bilinear filtering
|
||||
devCache.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
devCache.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
devCache.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // //LINEAR for Trilinear filtering
|
||||
devCache.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // LINEAR for Trilinear filtering
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -849,10 +854,10 @@ void D3DRenderer::setBaseScissor()
|
|||
}
|
||||
else
|
||||
{
|
||||
fWidth = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1;
|
||||
fHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1;
|
||||
min_x = pvrrc.fb_X_CLIP.min;
|
||||
min_y = pvrrc.fb_Y_CLIP.min;
|
||||
fWidth = (float)(pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1);
|
||||
fHeight = (float)(pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1);
|
||||
min_x = (float)pvrrc.fb_X_CLIP.min;
|
||||
min_y = (float)pvrrc.fb_Y_CLIP.min;
|
||||
if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer)
|
||||
{
|
||||
min_x *= config::RenderToTextureUpscale;
|
||||
|
@ -1010,7 +1015,10 @@ bool D3DRenderer::Render()
|
|||
}
|
||||
verifyWin(device->SetDepthStencilSurface(depthSurface));
|
||||
matrices.CalcMatrices(&pvrrc, width, height);
|
||||
verifyWin(device->SetVertexShaderConstantF(0, &matrices.GetNormalMatrix()[0][0], 4));
|
||||
// infamous DX9 half-pixel viewport shift
|
||||
// https://docs.microsoft.com/en-us/windows/win32/direct3d9/directly-mapping-texels-to-pixels
|
||||
glm::mat4 normalMat = glm::translate(glm::vec3(-1.f / width, 1.f / height, 0)) * matrices.GetNormalMatrix();
|
||||
verifyWin(device->SetVertexShaderConstantF(0, &normalMat[0][0], 4));
|
||||
|
||||
devCache.reset();
|
||||
devCache.SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
|
@ -1055,7 +1063,7 @@ bool D3DRenderer::Render()
|
|||
u8* fog_density = (u8*)&FOG_DENSITY;
|
||||
float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128
|
||||
s32 fog_den_exp = (s8)fog_density[0];
|
||||
float fog_den_float = fog_den_mant * powf(2.0f, fog_den_exp) * config::ExtraDepthScale;
|
||||
float fog_den_float = fog_den_mant * powf(2.0f, (float)fog_den_exp) * config::ExtraDepthScale;
|
||||
float fogDensityAndScale[4]= { fog_den_float, 1.f - FPU_SHAD_SCALE.scale_factor / 256.f, 0, 1 };
|
||||
device->SetPixelShaderConstantF(3, fogDensityAndScale, 1);
|
||||
|
||||
|
@ -1084,10 +1092,10 @@ bool D3DRenderer::Render()
|
|||
devCache.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
devCache.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
devCache.SetRenderState(D3DRS_TEXTUREFACTOR, 0xFFFFFFFF);
|
||||
|
||||
devCache.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
||||
devCache.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
devCache.SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
||||
devCache.SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
|
||||
|
||||
setBaseScissor();
|
||||
|
||||
|
@ -1186,8 +1194,15 @@ void D3DRenderer::updatePaletteTexture()
|
|||
|
||||
D3DLOCKED_RECT rect;
|
||||
verifyWin(paletteTexture->LockRect(0, &rect, nullptr, 0));
|
||||
verify(rect.Pitch == 32 * 4);
|
||||
memcpy(rect.pBits, palette32_ram, 32 * 32 * 4);
|
||||
if (rect.Pitch == 32 * sizeof(u32))
|
||||
memcpy(rect.pBits, palette32_ram, 32 * 32 * sizeof(u32));
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
for (int y = 0; y < 32; y++)
|
||||
memcpy(dst + y * rect.Pitch, palette32_ram + y * 32, 32 * sizeof(u32));
|
||||
}
|
||||
|
||||
paletteTexture->UnlockRect(0);
|
||||
device->SetTexture(1, paletteTexture);
|
||||
}
|
||||
|
@ -1202,8 +1217,14 @@ void D3DRenderer::updateFogTexture()
|
|||
|
||||
D3DLOCKED_RECT rect;
|
||||
verifyWin(fogTexture->LockRect(0, &rect, nullptr, 0));
|
||||
verify(rect.Pitch == 128);
|
||||
memcpy(rect.pBits, temp_tex_buffer, 128 * 2 * 1);
|
||||
if (rect.Pitch == 128)
|
||||
memcpy(rect.pBits, temp_tex_buffer, 128 * 2 * 1);
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
for (int y = 0; y < 2; y++)
|
||||
memcpy(dst + y * rect.Pitch, temp_tex_buffer + y * 128, 128);
|
||||
}
|
||||
fogTexture->UnlockRect(0);
|
||||
device->SetTexture(2, fogTexture);
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ const ComPtr<IDirect3DPixelShader9>& D3DShaders::getShader(bool pp_Texture, bool
|
|||
bool pp_Offset, u32 pp_FogCtrl, bool pp_BumpMap, bool fog_clamping,
|
||||
bool trilinear, bool palette, bool gouraud)
|
||||
{
|
||||
u32 hash = pp_Texture
|
||||
u32 hash = (int)pp_Texture
|
||||
| (pp_UseAlpha << 1)
|
||||
| (pp_IgnoreTexA << 2)
|
||||
| (pp_ShadInstr << 3)
|
||||
|
|
|
@ -44,52 +44,66 @@ void D3DTexture::UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mi
|
|||
default:
|
||||
return;
|
||||
}
|
||||
int mipmapLevels = 1;
|
||||
if (mipmapsIncluded)
|
||||
{
|
||||
// TODO Upload all mipmap levels
|
||||
int mipmapLevels = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT rect;
|
||||
while (true)
|
||||
{
|
||||
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);
|
||||
u32 levels = mipmapLevels;
|
||||
u32 usage = 0;
|
||||
if (mipmapped && !mipmapsIncluded)
|
||||
{
|
||||
levels = 0;
|
||||
usage = D3DUSAGE_AUTOGENMIPMAP;
|
||||
}
|
||||
theDXContext.getDevice()->CreateTexture(width, height, levels, usage, d3dFormat, D3DPOOL_MANAGED, &texture.get(), 0); // TODO the managed pool persists between device resets
|
||||
verify(texture != nullptr);
|
||||
}
|
||||
if (SUCCEEDED(texture->LockRect(0, &rect, nullptr, 0)))
|
||||
if (SUCCEEDED(texture->LockRect(mipmapLevels - 1, &rect, nullptr, 0)))
|
||||
break;
|
||||
D3DSURFACE_DESC desc;
|
||||
texture->GetLevelDesc(0, &desc);
|
||||
if (desc.Pool != D3DPOOL_DEFAULT)
|
||||
// it should be lockable so error out
|
||||
return;
|
||||
// RTT targets are created in the default pool and aren't lockable, so delete it and recreate it in the managed pool
|
||||
texture.reset();
|
||||
}
|
||||
if (width * bpp == (u32)rect.Pitch)
|
||||
memcpy(rect.pBits, temp_tex_buffer, width * bpp * height);
|
||||
else
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
for (int l = 0; l < height; l++)
|
||||
u32 w = mipmapLevels == 1 ? width : 1 << i;
|
||||
u32 h = mipmapLevels == 1 ? height : 1 << i;
|
||||
if (w * bpp == (u32)rect.Pitch)
|
||||
memcpy(rect.pBits, temp_tex_buffer, w * bpp * h);
|
||||
else
|
||||
{
|
||||
memcpy(dst, temp_tex_buffer, width * bpp);
|
||||
dst += rect.Pitch;
|
||||
temp_tex_buffer += width * bpp;
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
u8 *src = temp_tex_buffer;
|
||||
for (u32 l = 0; l < h; l++)
|
||||
{
|
||||
memcpy(dst, src, w * bpp);
|
||||
dst += rect.Pitch;
|
||||
src += w * bpp;
|
||||
}
|
||||
}
|
||||
texture->UnlockRect(mipmapLevels - i - 1);
|
||||
temp_tex_buffer += (1 << (2 * i)) * bpp;
|
||||
if (i < mipmapLevels - 1)
|
||||
if (FAILED(texture->LockRect(mipmapLevels - i - 2, &rect, nullptr, 0)))
|
||||
break;
|
||||
}
|
||||
texture->UnlockRect(0);
|
||||
}
|
||||
|
||||
bool D3DTexture::Delete()
|
||||
|
@ -100,3 +114,16 @@ bool D3DTexture::Delete()
|
|||
texture.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3DTexture::loadCustomTexture()
|
||||
{
|
||||
u32 size = custom_width * custom_height;
|
||||
u8 *p = custom_image_data;
|
||||
while (size--)
|
||||
{
|
||||
// RGBA -> BGRA
|
||||
std::swap(p[0], p[2]);
|
||||
p += 4;
|
||||
}
|
||||
CheckCustomTexture();
|
||||
}
|
||||
|
|
|
@ -28,13 +28,14 @@ public:
|
|||
void UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped,
|
||||
bool mipmapsIncluded = false) override;
|
||||
bool Delete() override;
|
||||
void loadCustomTexture();
|
||||
};
|
||||
|
||||
class D3DTextureCache final : public BaseTextureCache<D3DTexture>
|
||||
{
|
||||
public:
|
||||
D3DTextureCache() {
|
||||
D3DTexture::SetDirectXColorOrder(true); // TODO need to be reset to false by other renderers
|
||||
D3DTexture::SetDirectXColorOrder(true);
|
||||
}
|
||||
~D3DTextureCache() {
|
||||
Clear();
|
||||
|
|
|
@ -48,11 +48,13 @@ bool DXContext::Init()
|
|||
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pDevice.get())))
|
||||
return false;
|
||||
gui_init();
|
||||
overlay.init(pDevice);
|
||||
return ImGui_ImplDX9_Init(pDevice.get());
|
||||
}
|
||||
|
||||
void DXContext::Term()
|
||||
{
|
||||
overlay.term();
|
||||
ImGui_ImplDX9_Shutdown();
|
||||
pDevice.reset();
|
||||
pD3D.reset();
|
||||
|
@ -78,7 +80,7 @@ void DXContext::EndImGuiFrame()
|
|||
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
if (!overlay)
|
||||
if (!overlayOnly)
|
||||
{
|
||||
pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0);
|
||||
if (renderer != nullptr)
|
||||
|
@ -86,6 +88,15 @@ void DXContext::EndImGuiFrame()
|
|||
}
|
||||
if (SUCCEEDED(pDevice->BeginScene()))
|
||||
{
|
||||
if (overlayOnly)
|
||||
{
|
||||
if (crosshairsNeeded() || config::FloatVMUs)
|
||||
overlay.draw(screen_width, screen_height, config::FloatVMUs, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay.draw(screen_width, screen_height, true, false);
|
||||
}
|
||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
||||
pDevice->EndScene();
|
||||
}
|
||||
|
@ -109,6 +120,7 @@ void DXContext::resetDevice()
|
|||
{
|
||||
if (renderer != nullptr)
|
||||
((D3DRenderer *)renderer)->preReset();
|
||||
overlay.term();
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
HRESULT hr = pDevice->Reset(&d3dpp);
|
||||
if (hr == D3DERR_INVALIDCALL)
|
||||
|
@ -117,6 +129,7 @@ void DXContext::resetDevice()
|
|||
return;
|
||||
}
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
overlay.init(pDevice);
|
||||
if (renderer != nullptr)
|
||||
((D3DRenderer *)renderer)->postReset();
|
||||
}
|
||||
|
|
|
@ -18,61 +18,12 @@
|
|||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
#include "types.h"
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include "imgui_impl_dx9.h"
|
||||
#include "types.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;
|
||||
};
|
||||
#include "comptr.h"
|
||||
#include "d3d_overlay.h"
|
||||
|
||||
class DXContext
|
||||
{
|
||||
|
@ -84,7 +35,7 @@ public:
|
|||
const ComPtr<IDirect3D9>& getD3D() const { return pD3D; }
|
||||
const ComPtr<IDirect3DDevice9>& getDevice() const { return pDevice; }
|
||||
void resize();
|
||||
void setOverlay(bool overlay) { this->overlay = overlay; }
|
||||
void setOverlay(bool overlayOnly) { this->overlayOnly = overlayOnly; }
|
||||
std::string getDriverName() const {
|
||||
D3DADAPTER_IDENTIFIER9 id;
|
||||
pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id);
|
||||
|
@ -106,8 +57,9 @@ private:
|
|||
ComPtr<IDirect3D9> pD3D;
|
||||
ComPtr<IDirect3DDevice9> pDevice;
|
||||
D3DPRESENT_PARAMETERS d3dpp{};
|
||||
bool overlay = false;
|
||||
bool overlayOnly = false;
|
||||
HWND hWnd = nullptr;
|
||||
D3DOverlay overlay;
|
||||
};
|
||||
extern DXContext theDXContext;
|
||||
#endif
|
||||
|
|
|
@ -127,17 +127,6 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
|||
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
|
||||
|
@ -211,15 +200,6 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue