mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
246 lines
6.9 KiB
C++
246 lines
6.9 KiB
C++
#include "FramebufferD3D9.h"
|
|
|
|
#include "TextureD3D9.h"
|
|
#include "DeviceD3D9.h"
|
|
|
|
#include <d3d9.h>
|
|
|
|
namespace RBX
|
|
{
|
|
namespace Graphics
|
|
{
|
|
|
|
static IDirect3DSurface9* createRenderbuffer(IDirect3DDevice9* device9, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
|
|
{
|
|
IDirect3DSurface9* result = NULL;
|
|
|
|
D3DFORMAT format9 = static_cast<D3DFORMAT>(TextureD3D9::getInternalFormat(format));
|
|
D3DMULTISAMPLE_TYPE msaa9 = (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE;
|
|
|
|
HRESULT hr = D3DERR_INVALIDDEVICE;
|
|
|
|
if (Texture::isFormatDepth(format))
|
|
hr = device9->CreateDepthStencilSurface(width, height, format9, msaa9, 0, false, &result, NULL);
|
|
else
|
|
hr = device9->CreateRenderTarget(width, height, format9, msaa9, 0, false, &result, NULL);
|
|
|
|
if (FAILED(hr))
|
|
throw RBX::runtime_error("Error creating renderbuffer: %x", hr);
|
|
|
|
return result;
|
|
}
|
|
|
|
static IDirect3DSurface9* getSurface(shared_ptr<TextureD3D9> container, RenderbufferD3D9::OwnerType ot, unsigned level)
|
|
{
|
|
if (!container) return 0;
|
|
|
|
IDirect3DSurface9* ret = 0;
|
|
switch (ot)
|
|
{
|
|
case RenderbufferD3D9::Owner_Tex2:
|
|
static_cast<IDirect3DTexture9*>(container->getObject())->GetSurfaceLevel(level, &ret);
|
|
break;
|
|
case RenderbufferD3D9::Owner_CubePosX:
|
|
case RenderbufferD3D9::Owner_CubeNegX:
|
|
case RenderbufferD3D9::Owner_CubePosY:
|
|
case RenderbufferD3D9::Owner_CubeNegY:
|
|
case RenderbufferD3D9::Owner_CubePosZ:
|
|
case RenderbufferD3D9::Owner_CubeNegZ:
|
|
static_cast<IDirect3DCubeTexture9*>(container->getObject())->GetCubeMapSurface((D3DCUBEMAP_FACES)ot, level, &ret);
|
|
break;
|
|
default:
|
|
RBXASSERT(!"bad owner type for renderbuffer");
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
RenderbufferD3D9::RenderbufferD3D9(Device* device, shared_ptr<TextureD3D9> container, OwnerType tgt)
|
|
: Renderbuffer(device, container->getFormat(), container->getWidth(), container->getHeight(), 1)
|
|
, object(0)
|
|
, target(tgt)
|
|
, owner(container)
|
|
{
|
|
object = getSurface(owner, target, 0);
|
|
}
|
|
|
|
RenderbufferD3D9::RenderbufferD3D9(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples, IDirect3DSurface9* object)
|
|
: Renderbuffer(device, format, width, height, samples)
|
|
, object(object)
|
|
, target(Owner_None)
|
|
{
|
|
|
|
}
|
|
|
|
RenderbufferD3D9::RenderbufferD3D9(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
|
|
: Renderbuffer(device, format, width, height, samples)
|
|
, object(NULL)
|
|
, target(Owner_None)
|
|
{
|
|
IDirect3DDevice9* device9 = static_cast<DeviceD3D9*>(device)->getDevice9();
|
|
|
|
object = createRenderbuffer(device9, format, width, height, samples);
|
|
}
|
|
|
|
RenderbufferD3D9::~RenderbufferD3D9()
|
|
{
|
|
if (object)
|
|
object->Release();
|
|
}
|
|
|
|
void RenderbufferD3D9::onDeviceLost()
|
|
{
|
|
if (object)
|
|
{
|
|
object->Release();
|
|
object = NULL;
|
|
}
|
|
}
|
|
|
|
void RenderbufferD3D9::onDeviceRestored()
|
|
{
|
|
if (!object)
|
|
{
|
|
object = getSurface(owner, target, 0);
|
|
}
|
|
|
|
if (!object)
|
|
{
|
|
IDirect3DDevice9* device9 = static_cast<DeviceD3D9*>(device)->getDevice9();
|
|
object = createRenderbuffer(device9, format, width, height, samples);
|
|
}
|
|
}
|
|
|
|
void RenderbufferD3D9::updateObject(IDirect3DSurface9* value)
|
|
{
|
|
RBXASSERT(!object);
|
|
object = value;
|
|
}
|
|
|
|
FramebufferD3D9::FramebufferD3D9(Device* device, IDirect3DSurface9* colorSurface, IDirect3DSurface9* depthSurface)
|
|
: Framebuffer(device, 0, 0, 1)
|
|
{
|
|
RBXASSERT(colorSurface && depthSurface);
|
|
|
|
D3DSURFACE_DESC cdesc = {};
|
|
colorSurface->GetDesc(&cdesc);
|
|
|
|
D3DSURFACE_DESC ddesc = {};
|
|
depthSurface->GetDesc(&ddesc);
|
|
|
|
RBXASSERT(cdesc.Width == ddesc.Width && cdesc.Height == ddesc.Height);
|
|
|
|
width = cdesc.Width;
|
|
height = cdesc.Height;
|
|
|
|
color.push_back(shared_ptr<RenderbufferD3D9>(new RenderbufferD3D9(device, Texture::Format_RGBA8, width, height, 1, colorSurface)));
|
|
depth.reset(new RenderbufferD3D9(device, Texture::Format_D24S8, width, height, 1, depthSurface));
|
|
}
|
|
|
|
FramebufferD3D9::FramebufferD3D9(Device* device, const std::vector<shared_ptr<Renderbuffer> >& color, const shared_ptr<Renderbuffer>& depth)
|
|
: Framebuffer(device, 0, 0, 0)
|
|
, color(color)
|
|
, depth(depth)
|
|
{
|
|
RBXASSERT(!color.empty());
|
|
|
|
if (color.size() > device->getCaps().maxDrawBuffers)
|
|
throw RBX::runtime_error("Unsupported framebuffer configuration: too many buffers (%d)", color.size());
|
|
|
|
for (size_t i = 0; i < color.size(); ++i)
|
|
{
|
|
RenderbufferD3D9* buffer = static_cast<RenderbufferD3D9*>(color[i].get());
|
|
RBXASSERT(buffer);
|
|
RBXASSERT(!Texture::isFormatDepth(buffer->getFormat()));
|
|
|
|
if (i == 0)
|
|
{
|
|
width = buffer->getWidth();
|
|
height = buffer->getHeight();
|
|
samples = buffer->getSamples();
|
|
}
|
|
else
|
|
{
|
|
RBXASSERT(width == buffer->getWidth());
|
|
RBXASSERT(height == buffer->getHeight());
|
|
RBXASSERT(samples == buffer->getSamples());
|
|
}
|
|
}
|
|
|
|
if (depth)
|
|
{
|
|
RenderbufferD3D9* buffer = static_cast<RenderbufferD3D9*>(depth.get());
|
|
RBXASSERT(Texture::isFormatDepth(buffer->getFormat()));
|
|
|
|
RBXASSERT(width == buffer->getWidth());
|
|
RBXASSERT(height == buffer->getHeight());
|
|
RBXASSERT(samples == buffer->getSamples());
|
|
}
|
|
}
|
|
|
|
FramebufferD3D9::~FramebufferD3D9()
|
|
{
|
|
}
|
|
|
|
void FramebufferD3D9::download(void* data, unsigned int size)
|
|
{
|
|
RBXASSERT(size == width * height * 4);
|
|
|
|
IDirect3DSurface9* tempSurface = grabCopy();
|
|
|
|
D3DSURFACE_DESC surfaceDesc;
|
|
tempSurface->GetDesc(&surfaceDesc);
|
|
|
|
RBXASSERT(surfaceDesc.Format == D3DFMT_A8R8G8B8 || surfaceDesc.Format == D3DFMT_X8R8G8B8);
|
|
|
|
D3DLOCKED_RECT surfaceRect = {};
|
|
tempSurface->LockRect(&surfaceRect, NULL, 0);
|
|
|
|
RBXASSERT(static_cast<unsigned int>(surfaceRect.Pitch) >= width * 4);
|
|
|
|
for (unsigned int y = 0; y < height; ++y)
|
|
{
|
|
char* dataRow = static_cast<char*>(data) + y * width * 4;
|
|
memcpy(dataRow, static_cast<char*>(surfaceRect.pBits) + y * surfaceRect.Pitch, width * 4);
|
|
|
|
for (unsigned int x = 0; x < width; ++x)
|
|
std::swap(dataRow[x * 4 + 0], dataRow[x * 4 + 2]);
|
|
}
|
|
|
|
tempSurface->UnlockRect();
|
|
tempSurface->Release();
|
|
}
|
|
|
|
IDirect3DSurface9* FramebufferD3D9::grabCopy()
|
|
{
|
|
IDirect3DDevice9* device9 = static_cast<DeviceD3D9*>(device)->getDevice9();
|
|
|
|
RBXASSERT(!color.empty());
|
|
IDirect3DSurface9* colorSurface = static_cast<RenderbufferD3D9*>(color[0].get())->getObject();
|
|
|
|
D3DSURFACE_DESC desc;
|
|
colorSurface->GetDesc(&desc);
|
|
|
|
// Create a temporary system-memory surface
|
|
IDirect3DSurface9* systemSurface;
|
|
HRESULT hr = device9->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
|
|
|
|
if (FAILED(hr))
|
|
throw RBX::runtime_error("grabCopy failed: can't create off-screen surface: %x", hr);
|
|
|
|
// Copy data to the surface
|
|
hr = device9->GetRenderTargetData(colorSurface, systemSurface);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
systemSurface->Release();
|
|
|
|
throw RBX::runtime_error("grabCopy failed: can't read render-target data: %x", hr);
|
|
}
|
|
|
|
return systemSurface;
|
|
}
|
|
|
|
}
|
|
}
|