flycast/core/rend/dx9/d3d_texture.cpp

130 lines
3.1 KiB
C++

/*
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;
}
int mipmapLevels = 1;
if (mipmapsIncluded)
{
mipmapLevels = 0;
int dim = width;
while (dim != 0)
{
mipmapLevels++;
dim >>= 1;
}
}
D3DLOCKED_RECT rect;
while (true)
{
if (texture == nullptr)
{
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(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();
}
for (int i = 0; i < mipmapLevels; i++)
{
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
{
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;
}
}
bool D3DTexture::Delete()
{
if (!BaseTextureCacheData::Delete())
return false;
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();
}