WinRT: added render-to-texture support for D3D 11.1, via SDL_SetRenderTarget

This commit is contained in:
David Ludwig 2013-04-13 23:03:46 -04:00
parent b74856f7b7
commit e40e111591
2 changed files with 98 additions and 38 deletions

View file

@ -57,12 +57,12 @@ static void D3D11_WindowEvent(SDL_Renderer * renderer,
const SDL_WindowEvent *event); const SDL_WindowEvent *event);
static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, const SDL_Rect * rect, const void *srcPixels,
int pitch); int srcPitch);
static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, void **pixels, int *pitch); const SDL_Rect * rect, void **pixels, int *pitch);
static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
//static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture); static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
static int D3D11_UpdateViewport(SDL_Renderer * renderer); static int D3D11_UpdateViewport(SDL_Renderer * renderer);
static int D3D11_RenderClear(SDL_Renderer * renderer); static int D3D11_RenderClear(SDL_Renderer * renderer);
static int D3D11_RenderDrawPoints(SDL_Renderer * renderer, static int D3D11_RenderDrawPoints(SDL_Renderer * renderer,
@ -93,7 +93,11 @@ extern "C" SDL_RenderDriver D3D11_RenderDriver = {
D3D11_CreateRenderer, D3D11_CreateRenderer,
{ {
"direct3d 11.1", "direct3d 11.1",
(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), // flags. see SDL_RendererFlags (
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC |
SDL_RENDERER_TARGETTEXTURE
), // flags. see SDL_RendererFlags
2, // num_texture_formats 2, // num_texture_formats
{ // texture_formats { // texture_formats
SDL_PIXELFORMAT_RGB888, SDL_PIXELFORMAT_RGB888,
@ -165,7 +169,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->UpdateTexture = D3D11_UpdateTexture; renderer->UpdateTexture = D3D11_UpdateTexture;
renderer->LockTexture = D3D11_LockTexture; renderer->LockTexture = D3D11_LockTexture;
renderer->UnlockTexture = D3D11_UnlockTexture; renderer->UnlockTexture = D3D11_UnlockTexture;
//renderer->SetRenderTarget = D3D11_SetRenderTarget; renderer->SetRenderTarget = D3D11_SetRenderTarget;
renderer->UpdateViewport = D3D11_UpdateViewport; renderer->UpdateViewport = D3D11_UpdateViewport;
renderer->RenderClear = D3D11_RenderClear; renderer->RenderClear = D3D11_RenderClear;
renderer->RenderDrawPoints = D3D11_RenderDrawPoints; renderer->RenderDrawPoints = D3D11_RenderDrawPoints;
@ -178,7 +182,6 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->DestroyTexture = D3D11_DestroyTexture; renderer->DestroyTexture = D3D11_DestroyTexture;
renderer->DestroyRenderer = D3D11_DestroyRenderer; renderer->DestroyRenderer = D3D11_DestroyRenderer;
renderer->info = D3D11_RenderDriver.info; renderer->info = D3D11_RenderDriver.info;
renderer->info.flags = SDL_RENDERER_ACCELERATED;
renderer->driverdata = data; renderer->driverdata = data;
// HACK: make sure the SDL_Renderer references the SDL_Window data now, in // HACK: make sure the SDL_Renderer references the SDL_Window data now, in
@ -752,7 +755,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
result = data->d3dDevice->CreateRenderTargetView( result = data->d3dDevice->CreateRenderTargetView(
backBuffer.Get(), backBuffer.Get(),
nullptr, nullptr,
&data->renderTargetView &data->mainRenderTargetView
); );
if (FAILED(result)) { if (FAILED(result)) {
WIN_SetErrorFromHRESULT(__FUNCTION__, result); WIN_SetErrorFromHRESULT(__FUNCTION__, result);
@ -781,7 +784,7 @@ D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
{ {
ID3D11RenderTargetView* nullViews[] = {nullptr}; ID3D11RenderTargetView* nullViews[] = {nullptr};
data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
data->renderTargetView = nullptr; data->mainRenderTargetView = nullptr;
data->d3dContext->Flush(); data->d3dContext->Flush();
result = D3D11_CreateWindowSizeDependentResources(renderer); result = D3D11_CreateWindowSizeDependentResources(renderer);
if (FAILED(result)) { if (FAILED(result)) {
@ -860,11 +863,22 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
textureDesc.Format = textureFormat; textureDesc.Format = textureFormat;
textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0; textureDesc.SampleDesc.Quality = 0;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
textureDesc.MiscFlags = 0; textureDesc.MiscFlags = 0;
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
} else {
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.CPUAccessFlags = 0;
}
if (texture->access == SDL_TEXTUREACCESS_TARGET) {
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
} else {
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
}
#if 0 #if 0
// Fill the texture with a non-black color, for debugging purposes: // Fill the texture with a non-black color, for debugging purposes:
const int numPixels = textureDesc.Width * textureDesc.Height; const int numPixels = textureDesc.Width * textureDesc.Height;
@ -893,6 +907,23 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
return -1; return -1;
} }
if (texture->access & SDL_TEXTUREACCESS_TARGET) {
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
result = rendererData->d3dDevice->CreateRenderTargetView(
textureData->mainTexture.Get(),
&renderTargetViewDesc,
&textureData->mainTextureRenderTargetView);
if (FAILED(result)) {
D3D11_DestroyTexture(renderer, texture);
WIN_SetErrorFromHRESULT(__FUNCTION__, result);
return -1;
}
}
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
resourceViewDesc.Format = textureDesc.Format; resourceViewDesc.Format = textureDesc.Format;
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
@ -931,40 +962,33 @@ D3D11_DestroyTexture(SDL_Renderer * renderer,
static int static int
D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, const SDL_Rect * rect, const void * srcPixels,
int pitch) int srcPitch)
{ {
D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; // Lock the texture, retrieving a buffer to write pixel data to:
D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; void * destPixels = NULL;
HRESULT result = S_OK; int destPitch = 0;
if (D3D11_LockTexture(renderer, texture, rect, &destPixels, &destPitch) != 0) {
D3D11_MAPPED_SUBRESOURCE textureMemory = {0}; // An error is already set. Attach some info to it, then return to
result = rendererData->d3dContext->Map( // the caller.
textureData->mainTexture.Get(), std::string errorMessage = string(__FUNCTION__ ", Lock Texture Failed: ") + SDL_GetError();
0, SDL_SetError(errorMessage.c_str());
D3D11_MAP_WRITE_DISCARD,
0,
&textureMemory
);
if (FAILED(result)) {
WIN_SetErrorFromHRESULT(__FUNCTION__, result);
return -1; return -1;
} }
// Copy pixel data to the locked texture's memory: // Copy pixel data to the locked texture's memory:
for (int y = 0; y < rect->h; ++y) { for (int y = 0; y < rect->h; ++y) {
memcpy( memcpy(
((Uint8 *)textureMemory.pData) + (textureMemory.RowPitch * y), ((Uint8 *)destPixels) + (destPitch * y),
((Uint8 *)pixels) + (pitch * y), ((Uint8 *)srcPixels) + (srcPitch * y),
pitch srcPitch
); );
} }
// Clean up a bit, then commit the texture's memory back to Direct3D: // Commit the texture's memory back to Direct3D:
rendererData->d3dContext->Unmap( D3D11_UnlockTexture(renderer, texture);
textureData->mainTexture.Get(),
0);
// Return to the caller:
return 0; return 0;
} }
@ -1056,6 +1080,29 @@ D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
textureData->lockedTexturePosition = XMINT2(0, 0); textureData->lockedTexturePosition = XMINT2(0, 0);
} }
static int
D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
{
D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
if (texture == NULL) {
rendererData->currentOffscreenRenderTargetView = nullptr;
return 0;
}
D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
if (!textureData->mainTextureRenderTargetView) {
std::string errorMessage = string(__FUNCTION__) + ": specified texture is not a render target";
SDL_SetError(errorMessage.c_str());
return -1;
}
rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView;
return 0;
}
static int static int
D3D11_UpdateViewport(SDL_Renderer * renderer) D3D11_UpdateViewport(SDL_Renderer * renderer)
{ {
@ -1177,6 +1224,17 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
return 0; return 0;
} }
static ComPtr<ID3D11RenderTargetView> &
D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)
{
D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
if (data->currentOffscreenRenderTargetView) {
return data->currentOffscreenRenderTargetView;
} else {
return data->mainRenderTargetView;
}
}
static int static int
D3D11_RenderClear(SDL_Renderer * renderer) D3D11_RenderClear(SDL_Renderer * renderer)
{ {
@ -1188,7 +1246,7 @@ D3D11_RenderClear(SDL_Renderer * renderer)
(renderer->a / 255.0f) (renderer->a / 255.0f)
}; };
data->d3dContext->ClearRenderTargetView( data->d3dContext->ClearRenderTargetView(
data->renderTargetView.Get(), D3D11_GetCurrentRenderTargetView(renderer).Get(),
colorRGBA colorRGBA
); );
return 0; return 0;
@ -1250,7 +1308,7 @@ D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
rendererData->d3dContext->OMSetRenderTargets( rendererData->d3dContext->OMSetRenderTargets(
1, 1,
rendererData->renderTargetView.GetAddressOf(), D3D11_GetCurrentRenderTargetView(renderer).GetAddressOf(),
nullptr nullptr
); );
} }
@ -1695,7 +1753,7 @@ D3D11_RenderPresent(SDL_Renderer * renderer)
// Discard the contents of the render target. // Discard the contents of the render target.
// This is a valid operation only when the existing contents will be entirely // This is a valid operation only when the existing contents will be entirely
// overwritten. If dirty or scroll rects are used, this call should be removed. // overwritten. If dirty or scroll rects are used, this call should be removed.
data->d3dContext->DiscardView(data->renderTargetView.Get()); data->d3dContext->DiscardView(data->mainRenderTargetView.Get());
// If the device was removed either by a disconnect or a driver upgrade, we // If the device was removed either by a disconnect or a driver upgrade, we
// must recreate all device resources. // must recreate all device resources.

View file

@ -37,7 +37,8 @@ typedef struct
Microsoft::WRL::ComPtr<ID3D11Device1> d3dDevice; Microsoft::WRL::ComPtr<ID3D11Device1> d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> d3dContext; Microsoft::WRL::ComPtr<ID3D11DeviceContext1> d3dContext;
Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain; Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> renderTargetView; Microsoft::WRL::ComPtr<ID3D11RenderTargetView> mainRenderTargetView;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> currentOffscreenRenderTargetView;
Microsoft::WRL::ComPtr<ID3D11InputLayout> inputLayout; Microsoft::WRL::ComPtr<ID3D11InputLayout> inputLayout;
Microsoft::WRL::ComPtr<ID3D11Buffer> vertexBuffer; Microsoft::WRL::ComPtr<ID3D11Buffer> vertexBuffer;
Microsoft::WRL::ComPtr<ID3D11VertexShader> vertexShader; Microsoft::WRL::ComPtr<ID3D11VertexShader> vertexShader;
@ -67,6 +68,7 @@ typedef struct
{ {
Microsoft::WRL::ComPtr<ID3D11Texture2D> mainTexture; Microsoft::WRL::ComPtr<ID3D11Texture2D> mainTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> mainTextureResourceView; Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> mainTextureResourceView;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> mainTextureRenderTargetView;
SDL_PixelFormat * pixelFormat; SDL_PixelFormat * pixelFormat;
Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture; Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
DirectX::XMINT2 lockedTexturePosition; DirectX::XMINT2 lockedTexturePosition;