diff options
Diffstat (limited to 'retrace/d3d8state_images.cpp')
-rw-r--r-- | retrace/d3d8state_images.cpp | 231 |
1 files changed, 162 insertions, 69 deletions
diff --git a/retrace/d3d8state_images.cpp b/retrace/d3d8state_images.cpp index 89d4e06d..ad23bd6c 100644 --- a/retrace/d3d8state_images.cpp +++ b/retrace/d3d8state_images.cpp @@ -26,9 +26,11 @@ #include <assert.h> #include <stdint.h> +#include <stdio.h> #include "image.hpp" -#include "json.hpp" +#include "state_writer.hpp" +#include "com_ptr.hpp" #include "d3d8imports.hpp" #include "d3dstate.hpp" @@ -36,128 +38,219 @@ namespace d3dstate { +image::Image * +ConvertImage(D3DFORMAT SrcFormat, + void *SrcData, + INT SrcPitch, + UINT Width, UINT Height); + + static image::Image * -getRenderTargetImage(IDirect3DDevice8 *pDevice, - IDirect3DSurface8 *pRenderTarget) { +getSurfaceImage(IDirect3DDevice8 *pDevice, + IDirect3DSurface8 *pSurface) { image::Image *image = NULL; + HRESULT hr; + + if (!pSurface) { + return NULL; + } + D3DSURFACE_DESC Desc; - IDirect3DSurface8 *pStagingSurface = NULL; + hr = pSurface->GetDesc(&Desc); + assert(SUCCEEDED(hr)); + D3DLOCKED_RECT LockedRect; - const unsigned char *src; - unsigned char *dst; + hr = pSurface->LockRect(&LockedRect, NULL, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK); + if (FAILED(hr)) { + return NULL; + } + + image = ConvertImage(Desc.Format, LockedRect.pBits, LockedRect.Pitch, Desc.Width, Desc.Height); + + pSurface->UnlockRect(); + + return image; +} + + +static image::Image * +getRenderTargetImage(IDirect3DDevice8 *pDevice, + IDirect3DSurface8 *pRenderTarget) { HRESULT hr; if (!pRenderTarget) { return NULL; } + D3DSURFACE_DESC Desc; hr = pRenderTarget->GetDesc(&Desc); assert(SUCCEEDED(hr)); - if (Desc.Format != D3DFMT_X8R8G8B8 && - Desc.Format != D3DFMT_A8R8G8B8 && - Desc.Format != D3DFMT_R5G6B5) { - std::cerr << "warning: unsupported D3DFORMAT " << Desc.Format << "\n"; - goto no_staging; - } - + com_ptr<IDirect3DSurface8> pStagingSurface; hr = pDevice->CreateImageSurface(Desc.Width, Desc.Height, Desc.Format, &pStagingSurface); if (FAILED(hr)) { - goto no_staging; + return NULL; } hr = pDevice->CopyRects(pRenderTarget, NULL, 0, pStagingSurface, NULL); if (FAILED(hr)) { - goto no_rendertargetdata; + std::cerr << "warning: GetRenderTargetData failed\n"; + return NULL; } - hr = pStagingSurface->LockRect(&LockedRect, NULL, D3DLOCK_READONLY); + return getSurfaceImage(pDevice, pStagingSurface); +} + + +image::Image * +getRenderTargetImage(IDirect3DDevice8 *pDevice) { + HRESULT hr; + + com_ptr<IDirect3DSurface8> pRenderTarget; + hr = pDevice->GetRenderTarget(&pRenderTarget); if (FAILED(hr)) { - goto no_rendertargetdata; + return NULL; } + assert(pRenderTarget); + + return getRenderTargetImage(pDevice, pRenderTarget); +} - image = new image::Image(Desc.Width, Desc.Height, 3, true); - if (!image) { - goto no_image; + +static image::Image * +getTextureImage(IDirect3DDevice8 *pDevice, + IDirect3DBaseTexture8 *pTexture, + D3DCUBEMAP_FACES FaceType, + UINT Level) +{ + HRESULT hr; + + if (!pTexture) { + return NULL; } - dst = image->start(); - src = (const unsigned char *)LockedRect.pBits; - for (unsigned y = 0; y < Desc.Height; ++y) { - if (Desc.Format == D3DFMT_R5G6B5) { - for (unsigned x = 0; x < Desc.Width; ++x) { - uint32_t pixel = ((const uint16_t *)src)[x]; - dst[3*x + 0] = (( pixel & 0x1f) * (2*0xff) + 0x1f) / (2*0x1f); - dst[3*x + 1] = (((pixel >> 5) & 0x3f) * (2*0xff) + 0x3f) / (2*0x3f); - dst[3*x + 2] = (( pixel >> 11 ) * (2*0xff) + 0x1f) / (2*0x1f); - dst[3*x + 3] = 0xff; - } - } else { - for (unsigned x = 0; x < Desc.Width; ++x) { - dst[3*x + 0] = src[4*x + 2]; - dst[3*x + 1] = src[4*x + 1]; - dst[3*x + 2] = src[4*x + 0]; - } - } + com_ptr<IDirect3DSurface8> pSurface; - src += LockedRect.Pitch; - dst += image->stride(); + D3DRESOURCETYPE Type = pTexture->GetType(); + switch (Type) { + case D3DRTYPE_TEXTURE: + assert(FaceType == D3DCUBEMAP_FACE_POSITIVE_X); + hr = reinterpret_cast<IDirect3DTexture8 *>(pTexture)->GetSurfaceLevel(Level, &pSurface); + break; + case D3DRTYPE_CUBETEXTURE: + hr = reinterpret_cast<IDirect3DCubeTexture8 *>(pTexture)->GetCubeMapSurface(FaceType, Level, &pSurface); + break; + default: + /* TODO: support volume textures */ + return NULL; + } + if (FAILED(hr) || !pSurface) { + return NULL; } -no_image: - pStagingSurface->UnlockRect(); -no_rendertargetdata: - pStagingSurface->Release(); -no_staging: - return image; + D3DSURFACE_DESC Desc; + hr = pSurface->GetDesc(&Desc); + assert(SUCCEEDED(hr)); + + if (Desc.Pool != D3DPOOL_DEFAULT || + Desc.Usage & D3DUSAGE_DYNAMIC) { + // Lockable texture + return getSurfaceImage(pDevice, pSurface); + } else if (Desc.Usage & D3DUSAGE_RENDERTARGET) { + // Rendertarget texture + return getRenderTargetImage(pDevice, pSurface); + } else { + // D3D constraints are such there is not much else that can be done. + return NULL; + } } -image::Image * -getRenderTargetImage(IDirect3DDevice8 *pDevice) { +void +dumpTextures(StateWriter &writer, IDirect3DDevice8 *pDevice) +{ HRESULT hr; - IDirect3DSurface8 *pRenderTarget = NULL; - hr = pDevice->GetRenderTarget(&pRenderTarget); - if (FAILED(hr)) { - return NULL; - } - assert(pRenderTarget); + writer.beginMember("textures"); + writer.beginObject(); - image::Image *image = NULL; - if (pRenderTarget) { - image = getRenderTargetImage(pDevice, pRenderTarget); - pRenderTarget->Release(); + for (DWORD Stage = 0; Stage < 8; ++Stage) { + com_ptr<IDirect3DBaseTexture8> pTexture; + hr = pDevice->GetTexture(Stage, &pTexture); + if (FAILED(hr)) { + continue; + } + + if (!pTexture) { + continue; + } + + D3DRESOURCETYPE Type = pTexture->GetType(); + + DWORD NumFaces = Type == D3DRTYPE_CUBETEXTURE ? 6 : 1; + DWORD NumLevels = pTexture->GetLevelCount(); + + for (DWORD Face = 0; Face < NumFaces; ++Face) { + for (DWORD Level = 0; Level < NumLevels; ++Level) { + image::Image *image; + image = getTextureImage(pDevice, pTexture, static_cast<D3DCUBEMAP_FACES>(Face), Level); + if (image) { + char label[128]; + if (Type == D3DRTYPE_CUBETEXTURE) { + _snprintf(label, sizeof label, "PS_RESOURCE_%lu_FACE_%lu_LEVEL_%lu", Stage, Face, Level); + } else { + _snprintf(label, sizeof label, "PS_RESOURCE_%lu_LEVEL_%lu", Stage, Level); + } + writer.beginMember(label); + writer.writeImage(image); + writer.endMember(); // PS_RESOURCE_* + delete image; + } + } + } } - return image; + writer.endObject(); + writer.endMember(); // textures } void -dumpFramebuffer(JSONWriter &json, IDirect3DDevice8 *pDevice) +dumpFramebuffer(StateWriter &writer, IDirect3DDevice8 *pDevice) { HRESULT hr; - json.beginMember("framebuffer"); - json.beginObject(); + writer.beginMember("framebuffer"); + writer.beginObject(); - IDirect3DSurface8 *pRenderTarget = NULL; + com_ptr<IDirect3DSurface8> pRenderTarget; hr = pDevice->GetRenderTarget(&pRenderTarget); if (SUCCEEDED(hr) && pRenderTarget) { image::Image *image; image = getRenderTargetImage(pDevice, pRenderTarget); if (image) { - json.beginMember("RENDER_TARGET_0"); - json.writeImage(image, "UNKNOWN"); - json.endMember(); // RENDER_TARGET_* + writer.beginMember("RENDER_TARGET_0"); + writer.writeImage(image); + writer.endMember(); // RENDER_TARGET_* + delete image; } + } - pRenderTarget->Release(); + com_ptr<IDirect3DSurface8> pDepthStencil; + hr = pDevice->GetDepthStencilSurface(&pDepthStencil); + if (SUCCEEDED(hr) && pDepthStencil) { + image::Image *image; + image = getSurfaceImage(pDevice, pDepthStencil); + if (image) { + writer.beginMember("DEPTH_STENCIL"); + writer.writeImage(image); + writer.endMember(); // RENDER_TARGET_* + delete image; + } } - json.endObject(); - json.endMember(); // framebuffer + writer.endObject(); + writer.endMember(); // framebuffer } |