blob: bb2a92e045a72d97e98a59a00f6694f95e47c3a9 [file] [log] [blame]
//
// 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;
}
}