GPU: Use a texture directly for MakePixelTexture.
This makes it easier to do things with it.
This commit is contained in:
parent
2653e50200
commit
762b656ea2
20 changed files with 317 additions and 315 deletions
|
@ -662,11 +662,16 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
|
|||
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
|
||||
}
|
||||
|
||||
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height, u1, v1);
|
||||
Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height, u1, v1);
|
||||
if (pixelsTex) {
|
||||
draw_->BindTextures(0, 1, &pixelsTex);
|
||||
|
||||
Bind2DShader();
|
||||
DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
gpuStats.numUploads++;
|
||||
Bind2DShader();
|
||||
DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
gpuStats.numUploads++;
|
||||
|
||||
pixelsTex->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) {
|
||||
|
@ -701,7 +706,10 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
|||
|
||||
float u0 = 0.0f, u1 = 480.0f / 512.0f;
|
||||
float v0 = 0.0f, v1 = 1.0f;
|
||||
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272, u1, v1);
|
||||
Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272, u1, v1);
|
||||
if (!pixelsTex)
|
||||
return;
|
||||
draw_->BindTextures(0, 1, &pixelsTex);
|
||||
|
||||
int uvRotation = useBufferedRendering_ ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
|
||||
// TODO: Currently we can't access the texture from Draw.
|
||||
|
@ -712,6 +720,9 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
|||
|
||||
Bind2DShader();
|
||||
|
||||
if (needBackBufferYSwap_)
|
||||
std::swap(v0, v1);
|
||||
|
||||
DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags = flags | DRAWTEX_TO_BACKBUFFER;
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
|
@ -735,6 +746,8 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
|||
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1, uniforms);
|
||||
}*/
|
||||
|
||||
pixelsTex->Release();
|
||||
|
||||
// PresentationCommon sets all kinds of state, we can't rely on anything.
|
||||
gstate_c.Dirty(DIRTY_ALL);
|
||||
}
|
||||
|
|
|
@ -138,7 +138,6 @@ enum BindFramebufferColorFlags {
|
|||
enum DrawTextureFlags {
|
||||
DRAWTEX_NEAREST = 0,
|
||||
DRAWTEX_LINEAR = 1,
|
||||
DRAWTEX_KEEP_TEX = 2,
|
||||
DRAWTEX_KEEP_STENCIL_ALPHA = 4,
|
||||
DRAWTEX_TO_BACKBUFFER = 8,
|
||||
};
|
||||
|
@ -309,7 +308,7 @@ public:
|
|||
protected:
|
||||
virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
void SetViewport2D(int x, int y, int w, int h);
|
||||
virtual void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) = 0;
|
||||
virtual Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) = 0;
|
||||
virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) = 0;
|
||||
virtual void Bind2DShader() = 0;
|
||||
|
||||
|
|
|
@ -143,14 +143,6 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() {
|
|||
quadBuffer_->Release();
|
||||
fsQuadBuffer_->Release();
|
||||
|
||||
if (drawPixelsTex_)
|
||||
drawPixelsTex_->Release();
|
||||
if (drawPixelsTexView_)
|
||||
drawPixelsTexView_->Release();
|
||||
|
||||
// Temp FBOs cleared by FramebufferCommon.
|
||||
delete[] convBuf;
|
||||
|
||||
// Stencil cleanup
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (stencilMaskStates_[i])
|
||||
|
@ -186,69 +178,52 @@ void FramebufferManagerD3D11::SetDrawEngine(DrawEngineD3D11 *td) {
|
|||
drawEngine_ = td;
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
|
||||
if (drawPixelsTex_ && (drawPixelsTexW_ != width || drawPixelsTexH_ != height)) {
|
||||
drawPixelsTex_->Release();
|
||||
drawPixelsTex_ = nullptr;
|
||||
drawPixelsTexView_->Release();
|
||||
drawPixelsTexView_ = nullptr;
|
||||
}
|
||||
Draw::Texture *FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(data + byteStride * y);
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
ConvertRGB565ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
if (!drawPixelsTex_) {
|
||||
int usage = 0;
|
||||
D3D11_TEXTURE2D_DESC desc{};
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &drawPixelsTex_));
|
||||
ASSERT_SUCCESS(device_->CreateShaderResourceView(drawPixelsTex_, nullptr, &drawPixelsTexView_));
|
||||
drawPixelsTexW_ = width;
|
||||
drawPixelsTexH_ = height;
|
||||
}
|
||||
case GE_FORMAT_5551:
|
||||
ConvertRGBA5551ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
if (!drawPixelsTex_) {
|
||||
return;
|
||||
}
|
||||
case GE_FORMAT_4444:
|
||||
ConvertRGBA4444ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
context_->Map(drawPixelsTex_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
case GE_FORMAT_8888:
|
||||
ConvertRGBA8888ToBGRA8888(dst, src32, width);
|
||||
break;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)((u8 *)map.pData + map.RowPitch * y);
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
ConvertRGB565ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_5551:
|
||||
ConvertRGBA5551ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_4444:
|
||||
ConvertRGBA4444ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_8888:
|
||||
ConvertRGBA8888ToBGRA8888(dst, src32, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_INVALID:
|
||||
_dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels().");
|
||||
break;
|
||||
case GE_FORMAT_INVALID:
|
||||
_dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels().");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
context_->Unmap(drawPixelsTex_, 0);
|
||||
context_->PSSetShaderResources(0, 1, &drawPixelsTexView_);
|
||||
Draw::TextureDesc desc{
|
||||
Draw::TextureType::LINEAR2D,
|
||||
Draw::DataFormat::B8G8R8A8_UNORM,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
false,
|
||||
"DrawPixels",
|
||||
{ (uint8_t *)srcPixels },
|
||||
generateTexture,
|
||||
};
|
||||
Draw::Texture *tex = draw_->CreateTexture(desc);
|
||||
if (!tex)
|
||||
ERROR_LOG(G3D, "Failed to create drawpixels texture");
|
||||
return tex;
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) {
|
||||
|
|
|
@ -68,7 +68,7 @@ protected:
|
|||
|
||||
private:
|
||||
void Bind2DShader() override;
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
void SimpleBlit(
|
||||
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2,
|
||||
|
@ -79,12 +79,6 @@ private:
|
|||
ID3D11DeviceContext *context_;
|
||||
D3D_FEATURE_LEVEL featureLevel_;
|
||||
|
||||
// Used by DrawPixels
|
||||
ID3D11Texture2D *drawPixelsTex_ = nullptr;
|
||||
ID3D11ShaderResourceView *drawPixelsTexView_ = nullptr;
|
||||
int drawPixelsTexW_ = 0;
|
||||
int drawPixelsTexH_ = 0;
|
||||
|
||||
ID3D11VertexShader *quadVertexShader_;
|
||||
ID3D11PixelShader *quadPixelShader_;
|
||||
ID3D11InputLayout *quadInputLayout_;
|
||||
|
@ -95,8 +89,6 @@ private:
|
|||
const UINT quadOffset_ = 0;
|
||||
static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[2];
|
||||
|
||||
u8 *convBuf = nullptr;
|
||||
|
||||
ID3D11PixelShader *stencilUploadPS_ = nullptr;
|
||||
ID3D11VertexShader *stencilUploadVS_ = nullptr;
|
||||
ID3D11InputLayout *stencilUploadInputLayout_ = nullptr;
|
||||
|
|
|
@ -160,7 +160,9 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
|
|||
u16 h = dstBuffer->renderHeight;
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
if (!tex)
|
||||
return false;
|
||||
if (dstBuffer->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
|
||||
} else {
|
||||
|
@ -189,7 +191,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
|
|||
context_->IASetInputLayout(stencilUploadInputLayout_);
|
||||
context_->PSSetShader(stencilUploadPS_, nullptr, 0);
|
||||
context_->VSSetShader(stencilUploadVS_, nullptr, 0);
|
||||
context_->PSSetShaderResources(0, 1, &drawPixelsTexView_);
|
||||
draw_->BindTextures(0, 1, &tex);
|
||||
context_->RSSetState(stockD3D11.rasterStateNoCull);
|
||||
context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_);
|
||||
|
@ -237,6 +239,8 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
|
|||
context_->PSSetConstantBuffers(0, 1, &stencilValueBuffer_);
|
||||
context_->Draw(4, 0);
|
||||
}
|
||||
|
||||
tex->Release();
|
||||
RebindFramebuffer();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -131,13 +131,9 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
pFramebufferPixelShader = nullptr;
|
||||
}
|
||||
pFramebufferVertexDecl->Release();
|
||||
if (drawPixelsTex_) {
|
||||
drawPixelsTex_->Release();
|
||||
}
|
||||
for (auto &it : offscreenSurfaces_) {
|
||||
it.second.surface->Release();
|
||||
}
|
||||
delete [] convBuf;
|
||||
if (stencilUploadPS_) {
|
||||
stencilUploadPS_->Release();
|
||||
}
|
||||
|
@ -163,87 +159,52 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
drawEngine_ = td;
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
u8 *convBuf = NULL;
|
||||
D3DLOCKED_RECT rect;
|
||||
|
||||
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
|
||||
if (drawPixelsTex_ && (drawPixelsTexW_ != width || drawPixelsTexH_ != height)) {
|
||||
drawPixelsTex_->Release();
|
||||
drawPixelsTex_ = nullptr;
|
||||
}
|
||||
|
||||
if (!drawPixelsTex_) {
|
||||
int usage = 0;
|
||||
D3DPOOL pool = D3DPOOL_MANAGED;
|
||||
if (deviceEx_) {
|
||||
pool = D3DPOOL_DEFAULT;
|
||||
usage = D3DUSAGE_DYNAMIC;
|
||||
}
|
||||
HRESULT hr = device_->CreateTexture(width, height, 1, usage, D3DFMT_A8R8G8B8, pool, &drawPixelsTex_, NULL);
|
||||
if (FAILED(hr)) {
|
||||
drawPixelsTex_ = nullptr;
|
||||
ERROR_LOG(G3D, "Failed to create drawpixels texture");
|
||||
}
|
||||
drawPixelsTexW_ = width;
|
||||
drawPixelsTexH_ = height;
|
||||
}
|
||||
|
||||
if (!drawPixelsTex_) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawPixelsTex_->LockRect(0, &rect, NULL, D3DLOCK_DISCARD);
|
||||
|
||||
convBuf = (u8*)rect.pBits;
|
||||
|
||||
// Final format is BGRA(directx)
|
||||
if (srcPixelFormat != GE_FORMAT_8888 || srcStride != 512) {
|
||||
Draw::Texture *FramebufferManagerDX9::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(data + byteStride * y);
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
{
|
||||
const u16_le *src = (const u16_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(convBuf + rect.Pitch * y);
|
||||
ConvertRGB565ToBGRA8888(dst, src, width);
|
||||
}
|
||||
ConvertRGB565ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
// faster
|
||||
|
||||
case GE_FORMAT_5551:
|
||||
{
|
||||
const u16_le *src = (const u16_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(convBuf + rect.Pitch * y);
|
||||
ConvertRGBA5551ToBGRA8888(dst, src, width);
|
||||
}
|
||||
ConvertRGBA5551ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_4444:
|
||||
{
|
||||
const u16_le *src = (const u16_le *)srcPixels + srcStride * y;
|
||||
u8 *dst = (u8 *)(convBuf + rect.Pitch * y);
|
||||
ConvertRGBA4444ToBGRA8888((u32 *)dst, src, width);
|
||||
}
|
||||
ConvertRGBA4444ToBGRA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_8888:
|
||||
{
|
||||
const u32_le *src = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(convBuf + rect.Pitch * y);
|
||||
ConvertRGBA8888ToBGRA8888(dst, src, width);
|
||||
}
|
||||
ConvertRGBA8888ToBGRA8888(dst, src32, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_INVALID:
|
||||
_dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels().");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u32_le *src = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(convBuf + rect.Pitch * y);
|
||||
ConvertRGBA8888ToBGRA8888(dst, src, width);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
drawPixelsTex_->UnlockRect(0);
|
||||
device_->SetTexture(0, drawPixelsTex_);
|
||||
// D3DXSaveTextureToFile("game:\\cc.png", D3DXIFF_PNG, drawPixelsTex_, NULL);
|
||||
Draw::TextureDesc desc{
|
||||
Draw::TextureType::LINEAR2D,
|
||||
Draw::DataFormat::B8G8R8A8_UNORM,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
false,
|
||||
"DrawPixels",
|
||||
{ (uint8_t *)srcPixels },
|
||||
generateTexture,
|
||||
};
|
||||
Draw::Texture *tex = draw_->CreateTexture(desc);
|
||||
if (!tex)
|
||||
ERROR_LOG(G3D, "Failed to create drawpixels texture");
|
||||
return tex;
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) {
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "GPU/Common/FramebufferCommon.h"
|
||||
#include "ext/native/thin3d/thin3d.h"
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
|
@ -77,7 +76,7 @@ protected:
|
|||
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
|
||||
|
||||
private:
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
|
||||
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer);
|
||||
|
@ -85,17 +84,10 @@ private:
|
|||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9 deviceEx_;
|
||||
|
||||
// Used by DrawPixels
|
||||
LPDIRECT3DTEXTURE9 drawPixelsTex_ = nullptr;
|
||||
int drawPixelsTexW_;
|
||||
int drawPixelsTexH_;
|
||||
|
||||
LPDIRECT3DVERTEXSHADER9 pFramebufferVertexShader = nullptr;
|
||||
LPDIRECT3DPIXELSHADER9 pFramebufferPixelShader = nullptr;
|
||||
LPDIRECT3DVERTEXDECLARATION9 pFramebufferVertexDecl = nullptr;
|
||||
|
||||
u8 *convBuf = nullptr;
|
||||
|
||||
LPDIRECT3DPIXELSHADER9 stencilUploadPS_ = nullptr;
|
||||
LPDIRECT3DVERTEXSHADER9 stencilUploadVS_ = nullptr;
|
||||
bool stencilUploadFailed_ = false;
|
||||
|
|
|
@ -201,7 +201,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
|
|||
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
|
||||
device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0);
|
||||
|
||||
|
@ -220,7 +220,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
|
|||
device_->SetPixelShader(stencilUploadPS_);
|
||||
device_->SetVertexShader(stencilUploadVS_);
|
||||
|
||||
device_->SetTexture(0, drawPixelsTex_);
|
||||
draw_->BindTextures(0, 1, &tex);
|
||||
|
||||
shaderManagerDX9_->DirtyLastShader();
|
||||
textureCacheDX9_->ForgetLastTexture();
|
||||
|
@ -248,6 +248,8 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
|
|||
ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, hr);
|
||||
}
|
||||
}
|
||||
|
||||
tex->Release();
|
||||
dxstate.stencilMask.set(0xFF);
|
||||
dxstate.viewport.restore();
|
||||
RebindFramebuffer();
|
||||
|
|
|
@ -150,10 +150,6 @@ void FramebufferManagerGLES::DestroyDeviceObjects() {
|
|||
render_->DeleteProgram(draw2dprogram_);
|
||||
draw2dprogram_ = nullptr;
|
||||
}
|
||||
if (drawPixelsTex_) {
|
||||
render_->DeleteTexture(drawPixelsTex_);
|
||||
drawPixelsTex_ = 0;
|
||||
}
|
||||
if (stencilUploadProgram_) {
|
||||
render_->DeleteProgram(stencilUploadProgram_);
|
||||
stencilUploadProgram_ = nullptr;
|
||||
|
@ -170,52 +166,54 @@ FramebufferManagerGLES::~FramebufferManagerGLES() {
|
|||
delete [] convBuf_;
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
if (drawPixelsTex_) {
|
||||
render_->DeleteTexture(drawPixelsTex_);
|
||||
}
|
||||
|
||||
drawPixelsTex_ = render_->CreateTexture(GL_TEXTURE_2D);
|
||||
drawPixelsTexW_ = width;
|
||||
drawPixelsTexH_ = height;
|
||||
|
||||
drawPixelsTexFormat_ = srcPixelFormat;
|
||||
|
||||
Draw::Texture *FramebufferManagerGLES::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
// TODO: We can just change the texture format and flip some bits around instead of this.
|
||||
// Could share code with the texture cache perhaps.
|
||||
u32 neededSize = width * height * 4;
|
||||
u8 *convBuf = new u8[neededSize];
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)convBuf + width * y;
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
ConvertRGBA565ToRGBA8888((u32 *)dst, src16, width);
|
||||
break;
|
||||
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)(data + byteStride * y);
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
ConvertRGBA565ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_5551:
|
||||
ConvertRGBA5551ToRGBA8888((u32 *)dst, src16, width);
|
||||
break;
|
||||
case GE_FORMAT_5551:
|
||||
ConvertRGBA5551ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_4444:
|
||||
ConvertRGBA4444ToRGBA8888((u32 *)dst, src16, width);
|
||||
break;
|
||||
case GE_FORMAT_4444:
|
||||
ConvertRGBA4444ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_8888:
|
||||
memcpy(dst, src32, 4 * width);
|
||||
break;
|
||||
case GE_FORMAT_8888:
|
||||
memcpy(dst, src32, 4 * width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_INVALID:
|
||||
_dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels().");
|
||||
break;
|
||||
case GE_FORMAT_INVALID:
|
||||
_dbg_assert_msg_(G3D, false, "Invalid pixelFormat passed to DrawPixels().");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
render_->TextureImage(drawPixelsTex_, 0, width, height, Draw::DataFormat::R8G8B8A8_UNORM, convBuf, GLRAllocType::NEW, false);
|
||||
render_->FinalizeTexture(drawPixelsTex_, 0, false);
|
||||
};
|
||||
|
||||
// TODO: Return instead?
|
||||
render_->BindTexture(TEX_SLOT_PSP_TEXTURE, drawPixelsTex_);
|
||||
Draw::TextureDesc desc{
|
||||
Draw::TextureType::LINEAR2D,
|
||||
Draw::DataFormat::R8G8B8A8_UNORM,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
false,
|
||||
"DrawPixels",
|
||||
{ (uint8_t *)srcPixels },
|
||||
generateTexture,
|
||||
};
|
||||
Draw::Texture *tex = draw_->CreateTexture(desc);
|
||||
if (!tex)
|
||||
ERROR_LOG(G3D, "Failed to create drawpixels texture");
|
||||
return tex;
|
||||
}
|
||||
|
||||
// x, y, w, h are relative coordinates against destW/destH, which is not very intuitive.
|
||||
|
|
|
@ -73,7 +73,7 @@ private:
|
|||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void Bind2DShader() override;
|
||||
void CompileDraw2DProgram();
|
||||
|
||||
|
@ -81,14 +81,9 @@ private:
|
|||
|
||||
GLRenderManager *render_;
|
||||
|
||||
// Used by DrawPixels
|
||||
GLRTexture *drawPixelsTex_ = nullptr;
|
||||
GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID;
|
||||
int drawPixelsTexW_ = 0;
|
||||
int drawPixelsTexH_ = 0;
|
||||
|
||||
u8 *convBuf_ = nullptr;
|
||||
u32 convBufSize_ = 0;
|
||||
|
||||
GLRProgram *draw2dprogram_ = nullptr;
|
||||
|
||||
GLRProgram *stencilUploadProgram_ = nullptr;
|
||||
|
|
|
@ -177,8 +177,9 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe
|
|||
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height, u1, v1);
|
||||
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height, u1, v1);
|
||||
textureCacheGL_->ForgetLastTexture();
|
||||
draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex);
|
||||
|
||||
// We must bind the program after starting the render pass, and set the color mask after clearing.
|
||||
render_->SetScissor({ 0, 0, w, h });
|
||||
|
@ -211,6 +212,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe
|
|||
draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST);
|
||||
}
|
||||
|
||||
tex->Release();
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
RebindFramebuffer();
|
||||
return true;
|
||||
|
|
|
@ -270,7 +270,6 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
|||
outputFlags |= OutputFlags::BACKBUFFER_FLIPPED;
|
||||
}
|
||||
|
||||
// TODO, also deal with RB swizzle.
|
||||
PostShaderUniforms uniforms{};
|
||||
presentation_->CalculatePostShaderUniforms(desc.width, desc.height, false, &uniforms);
|
||||
|
||||
|
|
|
@ -85,8 +85,6 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
|
|||
}
|
||||
|
||||
FramebufferManagerVulkan::~FramebufferManagerVulkan() {
|
||||
delete[] convBuf_;
|
||||
|
||||
DeviceLost();
|
||||
}
|
||||
|
||||
|
@ -127,9 +125,6 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
|
|||
}
|
||||
|
||||
void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
||||
delete drawPixelsTex_;
|
||||
drawPixelsTex_ = nullptr;
|
||||
|
||||
if (fsBasicTex_ != VK_NULL_HANDLE) {
|
||||
vulkan2D_->PurgeFragmentShader(fsBasicTex_);
|
||||
vulkan_->Delete().QueueDeleteShaderModule(fsBasicTex_);
|
||||
|
@ -181,57 +176,23 @@ void FramebufferManagerVulkan::Init() {
|
|||
Resized();
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
if (drawPixelsTex_) {
|
||||
delete drawPixelsTex_;
|
||||
drawPixelsTex_ = nullptr;
|
||||
}
|
||||
|
||||
VkCommandBuffer initCmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
|
||||
|
||||
// There's only ever a few of these alive, don't need to stress the allocator with these big ones.
|
||||
// OR NOT! Hot Shot Golf (#12355) does tons of these in a frame in some situations! So actually,
|
||||
// we do use an allocator. In fact, I've now banned allocator-less textures.
|
||||
|
||||
drawPixelsTex_ = new VulkanTexture(vulkan_);
|
||||
drawPixelsTex_->SetTag("DrawPixels");
|
||||
if (!drawPixelsTex_->CreateDirect(initCmd, allocator_, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) {
|
||||
// out of memory?
|
||||
delete drawPixelsTex_;
|
||||
drawPixelsTex_ = nullptr;
|
||||
overrideImageView_ = VK_NULL_HANDLE;
|
||||
return;
|
||||
}
|
||||
// Initialize backbuffer texture for DrawPixels
|
||||
drawPixelsTexFormat_ = srcPixelFormat;
|
||||
|
||||
// TODO: We can just change the texture format and flip some bits around instead of this.
|
||||
// Could share code with the texture cache perhaps.
|
||||
// TODO: Could also convert directly into the pushbuffer easily.
|
||||
const uint8_t *data = srcPixels;
|
||||
if (srcPixelFormat != GE_FORMAT_8888 || srcStride != width) {
|
||||
u32 neededSize = width * height * 4;
|
||||
if (!convBuf_ || convBufSize_ < neededSize) {
|
||||
delete[] convBuf_;
|
||||
convBuf_ = new u8[neededSize];
|
||||
convBufSize_ = neededSize;
|
||||
}
|
||||
data = convBuf_;
|
||||
Draw::Texture *FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) {
|
||||
auto generateTexture = [&](uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
const u16_le *src16 = (const u16_le *)srcPixels + srcStride * y;
|
||||
const u32_le *src32 = (const u32_le *)srcPixels + srcStride * y;
|
||||
u32 *dst = (u32 *)convBuf_ + width * y;
|
||||
u32 *dst = (u32 *)(data + byteStride * y);
|
||||
switch (srcPixelFormat) {
|
||||
case GE_FORMAT_565:
|
||||
ConvertRGBA565ToRGBA8888((u32 *)dst, src16, width);
|
||||
ConvertRGBA565ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_5551:
|
||||
ConvertRGBA5551ToRGBA8888((u32 *)dst, src16, width);
|
||||
ConvertRGBA5551ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_4444:
|
||||
ConvertRGBA4444ToRGBA8888((u32 *)dst, src16, width);
|
||||
ConvertRGBA4444ToRGBA8888(dst, src16, width);
|
||||
break;
|
||||
|
||||
case GE_FORMAT_8888:
|
||||
|
@ -243,14 +204,28 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VkBuffer buffer;
|
||||
size_t offset = push_->Push(data, width * height * 4, &buffer);
|
||||
drawPixelsTex_->UploadMip(initCmd, 0, width, height, buffer, (uint32_t)offset, width);
|
||||
drawPixelsTex_->EndCreate(initCmd);
|
||||
// Hot Shot Golf (#12355) does tons of these in a frame in some situations! So actually,
|
||||
// we do use an allocator. In fact, I've now banned allocator-less textures.
|
||||
|
||||
overrideImageView_ = drawPixelsTex_->GetImageView();
|
||||
Draw::TextureDesc desc{
|
||||
Draw::TextureType::LINEAR2D,
|
||||
Draw::DataFormat::R8G8B8A8_UNORM,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
false,
|
||||
"DrawPixels",
|
||||
{ (uint8_t *)srcPixels },
|
||||
generateTexture,
|
||||
};
|
||||
// TODO: Use allocator_ somehow?
|
||||
Draw::Texture *tex = draw_->CreateTexture(desc);
|
||||
if (!tex)
|
||||
ERROR_LOG(G3D, "Failed to create drawpixels texture");
|
||||
return tex;
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) {
|
||||
|
@ -305,9 +280,7 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
|
|||
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
|
||||
if ((flags & DRAWTEX_KEEP_TEX) == 0)
|
||||
overrideImageView_ = VK_NULL_HANDLE;
|
||||
VkImageView view = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
|
||||
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||
VkBuffer vbuffer;
|
||||
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
|
||||
|
|
|
@ -79,7 +79,7 @@ protected:
|
|||
|
||||
private:
|
||||
// The returned texture does not need to be free'd, might be returned from a pool (currently single entry)
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
@ -88,12 +88,6 @@ private:
|
|||
|
||||
// Used to keep track of command buffers here but have moved all that into Thin3D.
|
||||
|
||||
// Used by DrawPixels
|
||||
VulkanTexture *drawPixelsTex_ = nullptr;
|
||||
GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID;
|
||||
u8 *convBuf_ = nullptr;
|
||||
u32 convBufSize_ = 0;
|
||||
|
||||
TextureCacheVulkan *textureCacheVulkan_ = nullptr;
|
||||
ShaderManagerVulkan *shaderManagerVulkan_ = nullptr;
|
||||
DrawEngineVulkan *drawEngineVulkan_ = nullptr;
|
||||
|
@ -118,9 +112,6 @@ private:
|
|||
VkSampler linearSampler_;
|
||||
VkSampler nearestSampler_;
|
||||
|
||||
// hack!
|
||||
VkImageView overrideImageView_ = VK_NULL_HANDLE;
|
||||
|
||||
// Simple 2D drawing engine.
|
||||
Vulkan2D *vulkan2D_;
|
||||
};
|
||||
|
|
|
@ -163,7 +163,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip
|
|||
u16 h = dstBuffer->renderHeight;
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
|
||||
if (dstBuffer->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
|
||||
} else {
|
||||
|
@ -176,7 +176,9 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip
|
|||
renderManager->SetScissor({ { 0, 0, },{ (uint32_t)w, (uint32_t)h } });
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE);
|
||||
|
||||
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(overrideImageView_, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||
draw_->BindTextures(0, 1, &tex);
|
||||
VkImageView drawPixelsImageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW);
|
||||
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(drawPixelsImageView, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||
|
||||
// Note: Even with skipZero, we don't necessarily start framebuffers at 0 in Vulkan. Clear anyway.
|
||||
// Not an actual clear, because we need to draw to alpha only as well.
|
||||
|
@ -212,7 +214,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip
|
|||
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle
|
||||
}
|
||||
|
||||
overrideImageView_ = VK_NULL_HANDLE;
|
||||
tex->Release();
|
||||
RebindFramebuffer();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "DataFormat.h"
|
||||
|
@ -519,6 +520,10 @@ struct DeviceCaps {
|
|||
std::string deviceName; // The device name to use when creating the thin3d context, to get the same one.
|
||||
};
|
||||
|
||||
// Use to write data directly to memory. initData is the pointer passed in TextureDesc.
|
||||
// Important: only write to the provided pointer, don't read from it.
|
||||
typedef std::function<void(uint8_t *data, const uint8_t *initData, uint32_t w, uint32_t h, uint32_t d, uint32_t byteStride, uint32_t sliceByteStride)> TextureCallback;
|
||||
|
||||
struct TextureDesc {
|
||||
TextureType type;
|
||||
DataFormat format;
|
||||
|
@ -530,7 +535,8 @@ struct TextureDesc {
|
|||
// Optional, for tracking memory usage.
|
||||
std::string tag;
|
||||
// Does not take ownership over pointed-to data.
|
||||
std::vector<uint8_t *> initData;
|
||||
std::vector<const uint8_t *> initData;
|
||||
TextureCallback initDataCallback;
|
||||
};
|
||||
|
||||
enum class RPAction {
|
||||
|
|
|
@ -689,16 +689,18 @@ public:
|
|||
~D3D11Texture() {
|
||||
if (tex)
|
||||
tex->Release();
|
||||
if (stagingTex)
|
||||
stagingTex->Release();
|
||||
if (view)
|
||||
view->Release();
|
||||
}
|
||||
|
||||
ID3D11Texture2D *tex = nullptr;
|
||||
ID3D11Texture2D *stagingTex = nullptr;
|
||||
ID3D11ShaderResourceView *view = nullptr;
|
||||
};
|
||||
|
||||
Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
||||
|
||||
if (!(GetDataFormatSupport(desc.format) & FMT_TEXTURE)) {
|
||||
// D3D11 does not support this format as a texture format.
|
||||
return nullptr;
|
||||
|
@ -720,25 +722,45 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
|||
descColor.Format = dataFormatToD3D11(desc.format);
|
||||
descColor.SampleDesc.Count = 1;
|
||||
descColor.SampleDesc.Quality = 0;
|
||||
|
||||
if (desc.initDataCallback) {
|
||||
descColor.Usage = D3D11_USAGE_STAGING;
|
||||
descColor.BindFlags = 0;
|
||||
descColor.MiscFlags = 0;
|
||||
descColor.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
HRESULT hr = device_->CreateTexture2D(&descColor, nullptr, &tex->stagingTex);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
descColor.Usage = D3D11_USAGE_DEFAULT;
|
||||
descColor.BindFlags = generateMips ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : D3D11_BIND_SHADER_RESOURCE;
|
||||
descColor.MiscFlags = generateMips ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||
descColor.CPUAccessFlags = 0;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA *initDataParam = nullptr;
|
||||
D3D11_SUBRESOURCE_DATA initData[12]{};
|
||||
if (desc.initData.size() && !generateMips) {
|
||||
std::vector<uint8_t> initDataBuffer[12];
|
||||
if (desc.initData.size() && !generateMips && !desc.initDataCallback) {
|
||||
int w = desc.width;
|
||||
int h = desc.height;
|
||||
int d = desc.depth;
|
||||
for (int i = 0; i < (int)desc.initData.size(); i++) {
|
||||
uint32_t byteStride = w * (uint32_t)DataFormatSizeInBytes(desc.format);
|
||||
initData[i].pSysMem = desc.initData[i];
|
||||
initData[i].SysMemPitch = (UINT)(w * DataFormatSizeInBytes(desc.format));
|
||||
initData[i].SysMemSlicePitch = (UINT)(w * h * DataFormatSizeInBytes(desc.format));
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
initData[i].SysMemPitch = (UINT)byteStride;
|
||||
initData[i].SysMemSlicePitch = (UINT)(h * byteStride);
|
||||
w = (w + 1) / 2;
|
||||
h = (h + 1) / 2;
|
||||
d = (d + 1) / 2;
|
||||
}
|
||||
initDataParam = initData;
|
||||
}
|
||||
|
||||
HRESULT hr = device_->CreateTexture2D(&descColor, (desc.initData.size() && !generateMips) ? initData : nullptr, &tex->tex);
|
||||
HRESULT hr = device_->CreateTexture2D(&descColor, initDataParam, &tex->tex);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
|
@ -749,8 +771,52 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
|||
return nullptr;
|
||||
}
|
||||
if (generateMips && desc.initData.size() >= 1) {
|
||||
context_->UpdateSubresource(tex->tex, 0, nullptr, desc.initData[0], desc.width * (int)DataFormatSizeInBytes(desc.format), 0);
|
||||
if (desc.initDataCallback) {
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = context_->Map(tex->stagingTex, 0, D3D11_MAP_WRITE, 0, &mapped);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
desc.initDataCallback((uint8_t *)mapped.pData, desc.initData[0], desc.width, desc.height, desc.depth, mapped.RowPitch, mapped.DepthPitch);
|
||||
context_->Unmap(tex->tex, 0);
|
||||
|
||||
context_->CopyResource(tex->stagingTex, tex->stagingTex);
|
||||
tex->stagingTex->Release();
|
||||
tex->stagingTex = nullptr;
|
||||
} else {
|
||||
uint32_t byteStride = desc.width * (uint32_t)DataFormatSizeInBytes(desc.format);
|
||||
context_->UpdateSubresource(tex->tex, 0, nullptr, desc.initData[0], byteStride, 0);
|
||||
}
|
||||
context_->GenerateMips(tex->view);
|
||||
} else if (desc.initDataCallback) {
|
||||
int w = desc.width;
|
||||
int h = desc.height;
|
||||
int d = desc.depth;
|
||||
for (int i = 0; i < (int)desc.initData.size(); i++) {
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = context_->Map(tex->stagingTex, i, D3D11_MAP_WRITE, 0, &mapped);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
if (i == 0) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
desc.initDataCallback((uint8_t *)mapped.pData, desc.initData[i], w, h, d, mapped.RowPitch, mapped.DepthPitch);
|
||||
context_->Unmap(tex->stagingTex, i);
|
||||
|
||||
w = (w + 1) / 2;
|
||||
h = (h + 1) / 2;
|
||||
d = (d + 1) / 2;
|
||||
}
|
||||
|
||||
context_->CopyResource(tex->tex, tex->stagingTex);
|
||||
tex->stagingTex->Release();
|
||||
tex->stagingTex = nullptr;
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ static const int primCountDivisor[] = {
|
|||
D3DFORMAT FormatToD3DFMT(DataFormat fmt) {
|
||||
switch (fmt) {
|
||||
case DataFormat::R8G8B8A8_UNORM: return D3DFMT_A8R8G8B8;
|
||||
case DataFormat::B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
|
||||
case DataFormat::R4G4B4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated
|
||||
case DataFormat::B4G4R4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // native
|
||||
case DataFormat::A4R4G4B4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated
|
||||
|
@ -312,7 +313,7 @@ public:
|
|||
void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler);
|
||||
|
||||
private:
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback);
|
||||
bool Create(const TextureDesc &desc);
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9EX deviceEx_;
|
||||
|
@ -384,8 +385,14 @@ bool D3D9Texture::Create(const TextureDesc &desc) {
|
|||
// In D3D9, after setting D3DUSAGE_AUTOGENMIPS, we can only access the top layer. The rest will be
|
||||
// automatically generated.
|
||||
int maxLevel = desc.generateMips ? 1 : (int)desc.initData.size();
|
||||
int w = desc.width;
|
||||
int h = desc.height;
|
||||
int d = desc.depth;
|
||||
for (int i = 0; i < maxLevel; i++) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
|
||||
SetImageData(0, 0, 0, w, h, d, i, 0, desc.initData[i], desc.initDataCallback);
|
||||
w = (w + 1) / 2;
|
||||
h = (h + 1) / 2;
|
||||
d = (d + 1) / 2;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -396,11 +403,10 @@ inline uint32_t Shuffle8888(uint32_t x) {
|
|||
return (x & 0xFF00FF00) | ((x >> 16) & 0xFF) | ((x << 16) & 0xFF0000);
|
||||
}
|
||||
|
||||
void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
|
||||
void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback) {
|
||||
if (!tex_)
|
||||
return;
|
||||
|
||||
|
||||
if (level == 0) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
@ -417,6 +423,14 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d
|
|||
D3DLOCKED_RECT rect;
|
||||
if (x == 0 && y == 0) {
|
||||
tex_->LockRect(level, &rect, NULL, D3DLOCK_DISCARD);
|
||||
|
||||
if (callback) {
|
||||
callback((uint8_t *)rect.pBits, data, width, height, depth, rect.Pitch, height * rect.Pitch);
|
||||
// Now this is the source. All conversions below support in-place.
|
||||
data = (const uint8_t *)rect.pBits;
|
||||
stride = rect.Pitch;
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
uint8_t *dest = (uint8_t *)rect.pBits + rect.Pitch * i;
|
||||
const uint8_t *source = data + stride * i;
|
||||
|
@ -431,7 +445,8 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d
|
|||
case DataFormat::A4R4G4B4_UNORM_PACK16:
|
||||
case DataFormat::A1R5G5B5_UNORM_PACK16:
|
||||
// Native
|
||||
memcpy(dest, source, width * sizeof(uint16_t));
|
||||
if (data != rect.pBits)
|
||||
memcpy(dest, source, width * sizeof(uint16_t));
|
||||
break;
|
||||
|
||||
case DataFormat::R8G8B8A8_UNORM:
|
||||
|
@ -441,7 +456,8 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d
|
|||
break;
|
||||
|
||||
case DataFormat::B8G8R8A8_UNORM:
|
||||
memcpy(dest, source, sizeof(uint32_t) * width);
|
||||
if (data != rect.pBits)
|
||||
memcpy(dest, source, sizeof(uint32_t) * width);
|
||||
break;
|
||||
default:
|
||||
// Unhandled data format copy.
|
||||
|
|
|
@ -655,7 +655,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
|
||||
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback);
|
||||
|
||||
GLRenderManager *render_;
|
||||
GLRTexture *tex_;
|
||||
|
@ -680,14 +680,15 @@ OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) :
|
|||
|
||||
canWrap_ = isPowerOf2(width_) && isPowerOf2(height_);
|
||||
mipLevels_ = desc.mipLevels;
|
||||
if (!desc.initData.size())
|
||||
if (desc.initData.empty())
|
||||
return;
|
||||
|
||||
int level = 0;
|
||||
for (auto data : desc.initData) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data);
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data, desc.initDataCallback);
|
||||
width_ = (width_ + 1) / 2;
|
||||
height_ = (height_ + 1) / 2;
|
||||
depth_ = (depth_ + 1) / 2;
|
||||
level++;
|
||||
}
|
||||
mipLevels_ = desc.generateMips ? desc.mipLevels : level;
|
||||
|
@ -699,7 +700,6 @@ OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) :
|
|||
generatedMips_ = true;
|
||||
}
|
||||
render->FinalizeTexture(tex_, mipLevels_, genMips);
|
||||
|
||||
}
|
||||
|
||||
OpenGLTexture::~OpenGLTexture() {
|
||||
|
@ -732,8 +732,8 @@ void MoveABit(u16 *dest, const u16 *src, size_t count) {
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
|
||||
if (width != width_ || height != height_ || depth != depth_) {
|
||||
void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback) {
|
||||
if ((width != width_ || height != height_ || depth != depth_) && level == 0) {
|
||||
// When switching to texStorage we need to handle this correctly.
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
@ -745,19 +745,28 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
|||
|
||||
size_t alignment = DataFormatSizeInBytes(format_);
|
||||
// Make a copy of data with stride eliminated.
|
||||
uint8_t *texData = new uint8_t[(size_t)(width * height * alignment)];
|
||||
uint8_t *texData = new uint8_t[(size_t)(width * height * depth * alignment)];
|
||||
|
||||
// Emulate support for DataFormat::A1R5G5B5_UNORM_PACK16.
|
||||
if (format_ == DataFormat::A1R5G5B5_UNORM_PACK16) {
|
||||
format_ = DataFormat::R5G5B5A1_UNORM_PACK16;
|
||||
for (int y = 0; y < height; y++) {
|
||||
MoveABit((u16 *)(texData + y * width * alignment), (const u16 *)(data + y * stride * alignment), width);
|
||||
if (callback) {
|
||||
callback(texData, data, width, height, depth, width * (int)alignment, height * width * (int)alignment);
|
||||
if (format_ == DataFormat::A1R5G5B5_UNORM_PACK16) {
|
||||
format_ = DataFormat::R5G5B5A1_UNORM_PACK16;
|
||||
MoveABit((u16 *)texData, (const u16 *)texData, width * height * depth);
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(texData + y * width * alignment, data + y * stride * alignment, width * alignment);
|
||||
// Emulate support for DataFormat::A1R5G5B5_UNORM_PACK16.
|
||||
if (format_ == DataFormat::A1R5G5B5_UNORM_PACK16) {
|
||||
format_ = DataFormat::R5G5B5A1_UNORM_PACK16;
|
||||
for (int y = 0; y < height; y++) {
|
||||
MoveABit((u16 *)(texData + y * width * alignment), (const u16 *)(data + y * stride * alignment), width);
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(texData + y * width * alignment, data + y * stride * alignment, width * alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_->TextureImage(tex_, level, width, height, format_, texData);
|
||||
}
|
||||
|
||||
|
|
|
@ -711,15 +711,22 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur
|
|||
if (desc.initData.size()) {
|
||||
int w = width_;
|
||||
int h = height_;
|
||||
int d = depth_;
|
||||
int i;
|
||||
for (i = 0; i < (int)desc.initData.size(); i++) {
|
||||
uint32_t offset;
|
||||
VkBuffer buf;
|
||||
size_t size = w * h * bytesPerPixel;
|
||||
offset = push->PushAligned((const void *)desc.initData[i], size, 16, &buf);
|
||||
size_t size = w * h * d * bytesPerPixel;
|
||||
if (desc.initDataCallback) {
|
||||
uint8_t *dest = (uint8_t *)push->PushAligned(size, &offset, &buf, 16);
|
||||
desc.initDataCallback(dest, desc.initData[0], w, h, d, w * bytesPerPixel, h * w * bytesPerPixel);
|
||||
} else {
|
||||
offset = push->PushAligned((const void *)desc.initData[i], size, 16, &buf);
|
||||
}
|
||||
vkTex_->UploadMip(cmd, i, w, h, buf, offset, w);
|
||||
w = (w + 1) / 2;
|
||||
h = (h + 1) / 2;
|
||||
d = (d + 1) / 2;
|
||||
}
|
||||
// Generate the rest of the mips automatically.
|
||||
for (; i < mipLevels_; i++) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue