// | |
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
// | |
// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. | |
#include "libGLESv2/renderer/SwapChain11.h" | |
#include "common/debug.h" | |
#include "libGLESv2/utilities.h" | |
#include "libGLESv2/renderer/renderer11_utils.h" | |
#include "libGLESv2/renderer/Renderer11.h" | |
#include "libGLESv2/Context.h" | |
#include "libGLESv2/main.h" | |
namespace rx | |
{ | |
SwapChain11::SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle, | |
GLenum backBufferFormat, GLenum depthBufferFormat) | |
: mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) | |
{ | |
mSwapChain = NULL; | |
mBackBuffer = NULL; | |
mBackBufferView = NULL; | |
mRenderTargetView = NULL; | |
mDepthStencil = NULL; | |
mDepthStencilView = NULL; | |
mOffscreenTexture = NULL; | |
mWidth = -1; | |
mHeight = -1; | |
} | |
SwapChain11::~SwapChain11() | |
{ | |
release(); | |
} | |
void SwapChain11::release() | |
{ | |
if (mSwapChain) | |
{ | |
mSwapChain->Release(); | |
mSwapChain = NULL; | |
} | |
if (mBackBuffer) | |
{ | |
mBackBuffer->Release(); | |
mBackBuffer = NULL; | |
} | |
if (mBackBufferView) | |
{ | |
mBackBufferView->Release(); | |
mBackBufferView = NULL; | |
} | |
if (mRenderTargetView) | |
{ | |
mRenderTargetView->Release(); | |
mRenderTargetView = NULL; | |
} | |
if (mDepthStencil) | |
{ | |
mDepthStencil->Release(); | |
mDepthStencil = NULL; | |
} | |
if (mDepthStencilView) | |
{ | |
mDepthStencilView->Release(); | |
mDepthStencilView = NULL; | |
} | |
if (mOffscreenTexture) | |
{ | |
mOffscreenTexture->Release(); | |
mOffscreenTexture = NULL; | |
} | |
if (mWindow) | |
mShareHandle = NULL; | |
} | |
EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) | |
{ | |
ID3D11Device *device = mRenderer->getDevice(); | |
if (device == NULL) | |
{ | |
return EGL_BAD_ACCESS; | |
} | |
// Release specific resources to free up memory for the new render target, while the | |
// old render target still exists for the purpose of preserving its contents. | |
if (mSwapChain) | |
{ | |
mSwapChain->Release(); | |
mSwapChain = NULL; | |
} | |
if (mBackBuffer) | |
{ | |
mBackBuffer->Release(); | |
mBackBuffer = NULL; | |
} | |
if (mBackBufferView) | |
{ | |
mBackBufferView->Release(); | |
mBackBufferView = NULL; | |
} | |
if (mRenderTargetView) // TODO: Preserve the render target content | |
{ | |
mRenderTargetView->Release(); | |
mRenderTargetView = NULL; | |
} | |
if (mOffscreenTexture) | |
{ | |
mOffscreenTexture->Release(); | |
mOffscreenTexture = NULL; | |
} | |
if (mDepthStencil) | |
{ | |
mDepthStencil->Release(); | |
mDepthStencil = NULL; | |
} | |
if (mDepthStencilView) | |
{ | |
mDepthStencilView->Release(); | |
mDepthStencilView = NULL; | |
} | |
HANDLE *pShareHandle = NULL; | |
if (!mWindow && mRenderer->getShareHandleSupport()) | |
{ | |
pShareHandle = &mShareHandle; | |
} | |
D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; | |
offscreenTextureDesc.Width = backbufferWidth; | |
offscreenTextureDesc.Height = backbufferHeight; | |
offscreenTextureDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); | |
offscreenTextureDesc.MipLevels = 1; | |
offscreenTextureDesc.ArraySize = 1; | |
offscreenTextureDesc.SampleDesc.Count = 1; | |
offscreenTextureDesc.SampleDesc.Quality = 0; | |
offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; | |
offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET; | |
offscreenTextureDesc.CPUAccessFlags = 0; | |
offscreenTextureDesc.MiscFlags = 0; // D3D11_RESOURCE_MISC_SHARED | |
HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); | |
if (FAILED(result)) | |
{ | |
ERR("Could not create offscreen texture: %08lX", result); | |
release(); | |
if (isDeviceLostError(result)) | |
{ | |
return EGL_CONTEXT_LOST; | |
} | |
else | |
{ | |
return EGL_BAD_ALLOC; | |
} | |
} | |
result = device->CreateRenderTargetView(mOffscreenTexture, NULL, &mRenderTargetView); | |
ASSERT(SUCCEEDED(result)); | |
if (mWindow) | |
{ | |
IDXGIFactory *factory = mRenderer->getDxgiFactory(); | |
DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; | |
swapChainDesc.BufferCount = 2; | |
swapChainDesc.BufferDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); | |
swapChainDesc.BufferDesc.Width = 1; | |
swapChainDesc.BufferDesc.Height = 1; | |
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; | |
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; | |
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; | |
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; | |
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
swapChainDesc.Flags = 0; | |
swapChainDesc.OutputWindow = mWindow; | |
swapChainDesc.SampleDesc.Count = 1; | |
swapChainDesc.SampleDesc.Quality = 0; | |
swapChainDesc.Windowed = TRUE; | |
result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); | |
if (FAILED(result)) | |
{ | |
ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); | |
release(); | |
if (isDeviceLostError(result)) | |
{ | |
return EGL_CONTEXT_LOST; | |
} | |
else | |
{ | |
return EGL_BAD_ALLOC; | |
} | |
} | |
result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBuffer); | |
ASSERT(SUCCEEDED(result)); | |
result = device->CreateRenderTargetView(mBackBuffer, NULL, &mBackBufferView); | |
ASSERT(SUCCEEDED(result)); | |
} | |
if (mDepthBufferFormat != GL_NONE) | |
{ | |
D3D11_TEXTURE2D_DESC depthStencilDesc = {0}; | |
depthStencilDesc.Width = backbufferWidth; | |
depthStencilDesc.Height = backbufferHeight; | |
depthStencilDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mDepthBufferFormat); | |
depthStencilDesc.MipLevels = 1; | |
depthStencilDesc.ArraySize = 1; | |
depthStencilDesc.SampleDesc.Count = 1; | |
depthStencilDesc.SampleDesc.Quality = 0; | |
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; | |
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; | |
depthStencilDesc.CPUAccessFlags = 0; | |
depthStencilDesc.MiscFlags = 0; | |
result = device->CreateTexture2D(&depthStencilDesc, NULL, &mDepthStencil); | |
if (FAILED(result)) | |
{ | |
ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); | |
release(); | |
if (isDeviceLostError(result)) | |
{ | |
return EGL_CONTEXT_LOST; | |
} | |
else | |
{ | |
return EGL_BAD_ALLOC; | |
} | |
} | |
result = device->CreateDepthStencilView(mDepthStencil, NULL, &mDepthStencilView); | |
ASSERT(SUCCEEDED(result)); | |
} | |
mWidth = backbufferWidth; | |
mHeight = backbufferHeight; | |
return EGL_SUCCESS; | |
} | |
// parameters should be validated/clamped by caller | |
EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) | |
{ | |
if (!mSwapChain) | |
{ | |
return EGL_SUCCESS; | |
} | |
ID3D11Device *device = mRenderer->getDevice(); | |
// TODO | |
UNIMPLEMENTED(); | |
return EGL_SUCCESS; | |
} | |
// Increments refcount on view. | |
// caller must Release() the returned view | |
ID3D11RenderTargetView *SwapChain11::getRenderTarget() | |
{ | |
if (mRenderTargetView) | |
{ | |
mRenderTargetView->AddRef(); | |
} | |
return mRenderTargetView; | |
} | |
// Increments refcount on view. | |
// caller must Release() the returned view | |
ID3D11DepthStencilView *SwapChain11::getDepthStencil() | |
{ | |
if (mDepthStencilView) | |
{ | |
mDepthStencilView->AddRef(); | |
} | |
return mDepthStencilView; | |
} | |
// Increments refcount on texture. | |
// caller must Release() the returned texture | |
ID3D11Texture2D *SwapChain11::getOffscreenTexture() | |
{ | |
if (mOffscreenTexture) | |
{ | |
mOffscreenTexture->AddRef(); | |
} | |
return mOffscreenTexture; | |
} | |
} |