blob: ad23bd6cf53ac03762d62583f28b9a3ccbc15063 [file] [log] [blame]
/**************************************************************************
*
* Copyright 2011-2012 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "image.hpp"
#include "state_writer.hpp"
#include "com_ptr.hpp"
#include "d3d8imports.hpp"
#include "d3dstate.hpp"
namespace d3dstate {
image::Image *
ConvertImage(D3DFORMAT SrcFormat,
void *SrcData,
INT SrcPitch,
UINT Width, UINT Height);
static image::Image *
getSurfaceImage(IDirect3DDevice8 *pDevice,
IDirect3DSurface8 *pSurface) {
image::Image *image = NULL;
HRESULT hr;
if (!pSurface) {
return NULL;
}
D3DSURFACE_DESC Desc;
hr = pSurface->GetDesc(&Desc);
assert(SUCCEEDED(hr));
D3DLOCKED_RECT LockedRect;
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));
com_ptr<IDirect3DSurface8> pStagingSurface;
hr = pDevice->CreateImageSurface(Desc.Width, Desc.Height, Desc.Format, &pStagingSurface);
if (FAILED(hr)) {
return NULL;
}
hr = pDevice->CopyRects(pRenderTarget, NULL, 0, pStagingSurface, NULL);
if (FAILED(hr)) {
std::cerr << "warning: GetRenderTargetData failed\n";
return NULL;
}
return getSurfaceImage(pDevice, pStagingSurface);
}
image::Image *
getRenderTargetImage(IDirect3DDevice8 *pDevice) {
HRESULT hr;
com_ptr<IDirect3DSurface8> pRenderTarget;
hr = pDevice->GetRenderTarget(&pRenderTarget);
if (FAILED(hr)) {
return NULL;
}
assert(pRenderTarget);
return getRenderTargetImage(pDevice, pRenderTarget);
}
static image::Image *
getTextureImage(IDirect3DDevice8 *pDevice,
IDirect3DBaseTexture8 *pTexture,
D3DCUBEMAP_FACES FaceType,
UINT Level)
{
HRESULT hr;
if (!pTexture) {
return NULL;
}
com_ptr<IDirect3DSurface8> pSurface;
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;
}
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;
}
}
void
dumpTextures(StateWriter &writer, IDirect3DDevice8 *pDevice)
{
HRESULT hr;
writer.beginMember("textures");
writer.beginObject();
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;
}
}
}
}
writer.endObject();
writer.endMember(); // textures
}
void
dumpFramebuffer(StateWriter &writer, IDirect3DDevice8 *pDevice)
{
HRESULT hr;
writer.beginMember("framebuffer");
writer.beginObject();
com_ptr<IDirect3DSurface8> pRenderTarget;
hr = pDevice->GetRenderTarget(&pRenderTarget);
if (SUCCEEDED(hr) && pRenderTarget) {
image::Image *image;
image = getRenderTargetImage(pDevice, pRenderTarget);
if (image) {
writer.beginMember("RENDER_TARGET_0");
writer.writeImage(image);
writer.endMember(); // RENDER_TARGET_*
delete image;
}
}
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;
}
}
writer.endObject();
writer.endMember(); // framebuffer
}
} /* namespace d3dstate */