diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp index 3ba765769..0da2c7697 100644 --- a/src/render/direct3d11/SDL_render_d3d11.cpp +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -53,32 +53,32 @@ using namespace Windows::UI::Core; static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags); static void D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event); -//static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); -//static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, -// const SDL_Rect * rect, const void *pixels, -// int pitch); +static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); //static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, // const SDL_Rect * rect, void **pixels, int *pitch); //static void D3D11_UnlockTexture(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_RenderClear(SDL_Renderer * renderer); +static int D3D11_RenderClear(SDL_Renderer * renderer); //static int D3D11_RenderDrawPoints(SDL_Renderer * renderer, // const SDL_FPoint * points, int count); //static int D3D11_RenderDrawLines(SDL_Renderer * renderer, // const SDL_FPoint * points, int count); //static int D3D11_RenderFillRects(SDL_Renderer * renderer, // const SDL_FRect * rects, int count); -//static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, -// const SDL_Rect * srcrect, const SDL_FRect * dstrect); +static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_FRect * dstrect); //static int D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, // const SDL_Rect * srcrect, const SDL_FRect * dstrect, // const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip); //static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, // Uint32 format, void * pixels, int pitch); static void D3D11_RenderPresent(SDL_Renderer * renderer); -//static void D3D11_DestroyTexture(SDL_Renderer * renderer, -// SDL_Texture * texture); +static void D3D11_DestroyTexture(SDL_Renderer * renderer, + SDL_Texture * texture); static void D3D11_DestroyRenderer(SDL_Renderer * renderer); /* Direct3D 11.1 Internal Functions */ @@ -91,10 +91,10 @@ extern "C" { SDL_RenderDriver D3D11_RenderDriver = { D3D11_CreateRenderer, { - "direct3d", + "direct3d 11.1", (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE), 1, - {SDL_PIXELFORMAT_ARGB8888}, + {SDL_PIXELFORMAT_RGB888}, 0, 0} }; @@ -132,21 +132,21 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) data->renderTargetSize = XMFLOAT2(0, 0); renderer->WindowEvent = D3D11_WindowEvent; - //renderer->CreateTexture = D3D11_CreateTexture; - //renderer->UpdateTexture = D3D11_UpdateTexture; + renderer->CreateTexture = D3D11_CreateTexture; + renderer->UpdateTexture = D3D11_UpdateTexture; //renderer->LockTexture = D3D11_LockTexture; //renderer->UnlockTexture = D3D11_UnlockTexture; //renderer->SetRenderTarget = D3D11_SetRenderTarget; renderer->UpdateViewport = D3D11_UpdateViewport; - //renderer->RenderClear = D3D11_RenderClear; + renderer->RenderClear = D3D11_RenderClear; //renderer->RenderDrawPoints = D3D11_RenderDrawPoints; //renderer->RenderDrawLines = D3D11_RenderDrawLines; //renderer->RenderFillRects = D3D11_RenderFillRects; - //renderer->RenderCopy = D3D11_RenderCopy; + renderer->RenderCopy = D3D11_RenderCopy; //renderer->RenderCopyEx = D3D11_RenderCopyEx; //renderer->RenderReadPixels = D3D11_RenderReadPixels; renderer->RenderPresent = D3D11_RenderPresent; - //renderer->DestroyTexture = D3D11_DestroyTexture; + renderer->DestroyTexture = D3D11_DestroyTexture; renderer->DestroyRenderer = D3D11_DestroyRenderer; renderer->info = D3D11_RenderDriver.info; renderer->info.flags = SDL_RENDERER_ACCELERATED; @@ -166,6 +166,8 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) return NULL; } + // TODO, WinRT: fill in renderer->info.texture_formats where appropriate + return renderer; } @@ -720,12 +722,210 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } +static int +D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + D3D11_TextureData *textureData; + HRESULT result; + + textureData = new D3D11_TextureData; + if (!textureData) { + SDL_OutOfMemory(); + return -1; + } + textureData->pixelFormat = SDL_AllocFormat(texture->format); + + texture->driverdata = textureData; + + const int pixelSizeInBytes = textureData->pixelFormat->BytesPerPixel; + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + textureDesc.Width = texture->w; + textureDesc.Height = texture->h; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DYNAMIC; + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + textureDesc.MiscFlags = 0; + + const int numPixels = textureDesc.Width * textureDesc.Height; + std::vector initialTexturePixels(numPixels * pixelSizeInBytes, 0x00); + + // Fill the texture with a non-black color, for debugging purposes: + //for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) { + // initialTexturePixels[i+0] = 0xff; + // initialTexturePixels[i+1] = 0xff; + // initialTexturePixels[i+2] = 0x00; + // initialTexturePixels[i+3] = 0xff; + //} + + D3D11_SUBRESOURCE_DATA initialTextureData = {0}; + initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]); + initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes; + initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes; + result = rendererData->d3dDevice->CreateTexture2D( + &textureDesc, + &initialTextureData, + &textureData->mainTexture + ); + if (FAILED(result)) { + D3D11_DestroyTexture(renderer, texture); + WIN_SetErrorFromHRESULT(__FUNCTION__, result); + return -1; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; + resourceViewDesc.Format = textureDesc.Format; + resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceViewDesc.Texture2D.MostDetailedMip = 0; + resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; + result = rendererData->d3dDevice->CreateShaderResourceView( + textureData->mainTexture.Get(), + &resourceViewDesc, + &textureData->mainTextureResourceView + ); + if (FAILED(result)) { + D3D11_DestroyTexture(renderer, texture); + WIN_SetErrorFromHRESULT(__FUNCTION__, result); + return -1; + } + + return 0; +} + +static void +D3D11_DestroyTexture(SDL_Renderer * renderer, + SDL_Texture * texture) +{ + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + + if (textureData) { + if (textureData->pixelFormat) { + SDL_FreeFormat(textureData->pixelFormat); + textureData->pixelFormat = NULL; + } + + delete textureData; + texture = NULL; + texture->driverdata = NULL; + } +} + +static int +D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + HRESULT result = S_OK; + + D3D11_MAPPED_SUBRESOURCE textureMemory = {0}; + result = rendererData->d3dContext->Map( + textureData->mainTexture.Get(), + 0, + D3D11_MAP_WRITE_DISCARD, + 0, + &textureMemory + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__, result); + return -1; + } + + // Copy pixel data to the locked texture's memory: + for (int y = 0; y < rect->h; ++y) { + memcpy( + ((Uint8 *)textureMemory.pData) + (textureMemory.RowPitch * y), + ((Uint8 *)pixels) + (pitch * y), + pitch + ); + } + + // Clean up a bit, then commit the texture's memory back to Direct3D: + rendererData->d3dContext->Unmap( + textureData->mainTexture.Get(), + 0); + + return 0; +} + static int D3D11_UpdateViewport(SDL_Renderer * renderer) { return 0; } +static int +D3D11_RenderClear(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + const float colorRGBA[] = { + renderer->r, + renderer->g, + renderer->b, + renderer->a + }; + data->d3dContext->ClearRenderTargetView( + data->renderTargetView.Get(), + colorRGBA + ); + return 0; +} + +static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_FRect * dstrect) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + //HRESULT result = S_OK; + + rendererData->d3dContext->OMSetRenderTargets( + 1, + rendererData->renderTargetView.GetAddressOf(), + nullptr + ); + + UINT stride = sizeof(VertexPositionColor); + UINT offset = 0; + rendererData->d3dContext->IASetVertexBuffers( + 0, + 1, + rendererData->vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + + rendererData->d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + rendererData->d3dContext->IASetInputLayout(rendererData->inputLayout.Get()); + + rendererData->d3dContext->VSSetShader( + rendererData->vertexShader.Get(), + nullptr, + 0 + ); + + rendererData->d3dContext->PSSetShader( + rendererData->pixelShader.Get(), + nullptr, + 0 + ); + + rendererData->d3dContext->PSSetShaderResources(0, 1, textureData->mainTextureResourceView.GetAddressOf()); + + rendererData->d3dContext->PSSetSamplers(0, 1, rendererData->mainSampler.GetAddressOf()); + + rendererData->d3dContext->Draw(4, 0); + + return 0; +} + static void D3D11_RenderPresent(SDL_Renderer * renderer) { diff --git a/src/render/direct3d11/SDL_render_d3d11_cpp.h b/src/render/direct3d11/SDL_render_d3d11_cpp.h index 644b8bd17..9baf3df57 100644 --- a/src/render/direct3d11/SDL_render_d3d11_cpp.h +++ b/src/render/direct3d11/SDL_render_d3d11_cpp.h @@ -34,8 +34,6 @@ typedef struct Microsoft::WRL::ComPtr vertexBuffer; Microsoft::WRL::ComPtr vertexShader; Microsoft::WRL::ComPtr pixelShader; - Microsoft::WRL::ComPtr mainTexture; - Microsoft::WRL::ComPtr mainTextureResourceView; Microsoft::WRL::ComPtr mainSampler; D3D_FEATURE_LEVEL featureLevel; unsigned int vertexCount; @@ -52,6 +50,9 @@ typedef struct typedef struct { + Microsoft::WRL::ComPtr mainTexture; + Microsoft::WRL::ComPtr mainTextureResourceView; + SDL_PixelFormat * pixelFormat; } D3D11_TextureData; struct VertexPositionColor diff --git a/src/video/windowsrt/SDL_winrtrenderer.cpp b/src/video/windowsrt/SDL_winrtrenderer.cpp index bb89580a8..a84fa7b2e 100644 --- a/src/video/windowsrt/SDL_winrtrenderer.cpp +++ b/src/video/windowsrt/SDL_winrtrenderer.cpp @@ -7,6 +7,7 @@ extern "C" { #include "SDL_syswm.h" +#include "../../core/windows/SDL_windows.h" } using namespace DirectX; @@ -18,167 +19,65 @@ using namespace Windows::Graphics::Display; // Constructor. SDL_winrtrenderer::SDL_winrtrenderer() : - m_mainTextureHelperSurface(NULL), m_sdlRenderer(NULL), - m_sdlRendererData(NULL) + m_sdlRendererData(NULL), + m_mainTexture(NULL) { } SDL_winrtrenderer::~SDL_winrtrenderer() { - if (m_mainTextureHelperSurface) { - SDL_FreeSurface(m_mainTextureHelperSurface); - m_mainTextureHelperSurface = NULL; + if (m_mainTexture) { + SDL_DestroyTexture(m_mainTexture); + m_mainTexture = NULL; } } void SDL_winrtrenderer::ResizeMainTexture(int w, int h) { - const int pixelSizeInBytes = 4; - - D3D11_TEXTURE2D_DESC textureDesc = {0}; - textureDesc.Width = w; - textureDesc.Height = h; - textureDesc.MipLevels = 1; - textureDesc.ArraySize = 1; - textureDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; - textureDesc.SampleDesc.Count = 1; - textureDesc.SampleDesc.Quality = 0; - textureDesc.Usage = D3D11_USAGE_DYNAMIC; - textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - textureDesc.MiscFlags = 0; - - const int numPixels = textureDesc.Width * textureDesc.Height; - std::vector initialTexturePixels(numPixels * pixelSizeInBytes, 0x00); - - // Fill the texture with a non-black color, for debugging purposes: - //for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) { - // initialTexturePixels[i+0] = 0xff; - // initialTexturePixels[i+1] = 0xff; - // initialTexturePixels[i+2] = 0x00; - // initialTexturePixels[i+3] = 0xff; - //} - - D3D11_SUBRESOURCE_DATA initialTextureData = {0}; - initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]); - initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes; - initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes; - DX::ThrowIfFailed( - m_sdlRendererData->d3dDevice->CreateTexture2D( - &textureDesc, - &initialTextureData, - &m_sdlRendererData->mainTexture - ) - ); - - if (m_mainTextureHelperSurface) { - SDL_FreeSurface(m_mainTextureHelperSurface); - m_mainTextureHelperSurface = NULL; - } - m_mainTextureHelperSurface = SDL_CreateRGBSurfaceFrom( - NULL, - textureDesc.Width, textureDesc.Height, - (pixelSizeInBytes * 8), - 0, // Use an nil pitch for now. This'll be filled in when updating the texture. - 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); // TODO, WinRT: calculate masks given the Direct3D-defined pixel format of the texture - if (m_mainTextureHelperSurface == NULL) { - DX::ThrowIfFailed(E_FAIL); // TODO, WinRT: generate a better error here, taking into account who's calling this function. + if (m_mainTexture) { + SDL_DestroyTexture(m_mainTexture); + m_mainTexture = NULL; } - D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; - resourceViewDesc.Format = textureDesc.Format; - resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - resourceViewDesc.Texture2D.MostDetailedMip = 0; - resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; - DX::ThrowIfFailed( - m_sdlRendererData->d3dDevice->CreateShaderResourceView( - m_sdlRendererData->mainTexture.Get(), - &resourceViewDesc, - &m_sdlRendererData->mainTextureResourceView) - ); + m_mainTexture = SDL_CreateTexture(m_sdlRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, w, h); +} + +static inline Platform::Exception ^ +WINRT_CreateExceptionWithSDLError() +{ + wchar_t * sdlErrorMessage = WIN_UTF8ToString(SDL_GetError()); + Platform::String ^ errorMessage = ref new Platform::String(sdlErrorMessage); + SDL_free(sdlErrorMessage); + throw ref new Platform::FailureException(errorMessage); } void SDL_winrtrenderer::Render(SDL_Surface * surface, SDL_Rect * rects, int numrects) { - const float blackColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - m_sdlRendererData->d3dContext->ClearRenderTargetView( - m_sdlRendererData->renderTargetView.Get(), - blackColor - ); + D3D11_TextureData * textureData = (D3D11_TextureData *)m_mainTexture->driverdata; + + SDL_SetRenderDrawColor(m_sdlRenderer, 0, 0, 0, 0); + if (SDL_RenderClear(m_sdlRenderer) != 0) { + throw WINRT_CreateExceptionWithSDLError(); + } // Only draw the screen once it is loaded (some loading is asynchronous). - if (!m_sdlRendererData->loadingComplete) - { + if (!m_sdlRendererData->loadingComplete) { return; } - if (!m_sdlRendererData->mainTextureResourceView) - { + if (!textureData->mainTextureResourceView) { return; } - // Update the main texture (for SDL usage). Start by mapping the SDL - // window's main texture to CPU-accessible memory: - D3D11_MAPPED_SUBRESOURCE textureMemory = {0}; - DX::ThrowIfFailed( - m_sdlRendererData->d3dContext->Map( - m_sdlRendererData->mainTexture.Get(), - 0, - D3D11_MAP_WRITE_DISCARD, - 0, - &textureMemory) - ); - - // Copy pixel data to the locked texture's memory: - m_mainTextureHelperSurface->pixels = textureMemory.pData; - m_mainTextureHelperSurface->pitch = textureMemory.RowPitch; - SDL_BlitSurface(surface, NULL, m_mainTextureHelperSurface, NULL); + // Update the main texture (for SDL usage). // TODO, WinRT: only update the requested rects (passed to SDL_UpdateWindowSurface), rather than everything + if (SDL_UpdateTexture(m_mainTexture, NULL, surface->pixels, surface->pitch) != 0) { + throw WINRT_CreateExceptionWithSDLError(); + } - // Clean up a bit, then commit the texture's memory back to Direct3D: - m_mainTextureHelperSurface->pixels = NULL; - m_mainTextureHelperSurface->pitch = 0; - m_sdlRendererData->d3dContext->Unmap( - m_sdlRendererData->mainTexture.Get(), - 0); - - m_sdlRendererData->d3dContext->OMSetRenderTargets( - 1, - m_sdlRendererData->renderTargetView.GetAddressOf(), - nullptr - ); - - UINT stride = sizeof(VertexPositionColor); - UINT offset = 0; - m_sdlRendererData->d3dContext->IASetVertexBuffers( - 0, - 1, - m_sdlRendererData->vertexBuffer.GetAddressOf(), - &stride, - &offset - ); - - m_sdlRendererData->d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - m_sdlRendererData->d3dContext->IASetInputLayout(m_sdlRendererData->inputLayout.Get()); - - m_sdlRendererData->d3dContext->VSSetShader( - m_sdlRendererData->vertexShader.Get(), - nullptr, - 0 - ); - - m_sdlRendererData->d3dContext->PSSetShader( - m_sdlRendererData->pixelShader.Get(), - nullptr, - 0 - ); - - m_sdlRendererData->d3dContext->PSSetShaderResources(0, 1, m_sdlRendererData->mainTextureResourceView.GetAddressOf()); - - m_sdlRendererData->d3dContext->PSSetSamplers(0, 1, m_sdlRendererData->mainSampler.GetAddressOf()); - - m_sdlRendererData->d3dContext->Draw(4, 0); + if (SDL_RenderCopy(m_sdlRenderer, m_mainTexture, NULL, NULL) != 0) { + throw WINRT_CreateExceptionWithSDLError(); + } } // Method to deliver the final image to the display. diff --git a/src/video/windowsrt/SDL_winrtrenderer.h b/src/video/windowsrt/SDL_winrtrenderer.h index 061cdb3a2..f99d67c36 100644 --- a/src/video/windowsrt/SDL_winrtrenderer.h +++ b/src/video/windowsrt/SDL_winrtrenderer.h @@ -29,5 +29,5 @@ internal: protected private: // UpdateWindowSurface helper objects - SDL_Surface * m_mainTextureHelperSurface; + SDL_Texture * m_mainTexture; };