blob: 1dd88a2bbb34e62565544659846ff1c3a0723ca7 [file] [log] [blame]
//
// Copyright (c) 2002-2010 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.
//
// Surface.cpp: Implements the egl::Surface class, representing a drawing surface
// such as the client area of a window, including any back buffers.
// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
#include "libEGL/Surface.h"
#include "common/debug.h"
#include "libEGL/main.h"
#include "libEGL/Display.h"
namespace egl
{
Surface::Surface(Display *display, IDirect3DSwapChain9 *swapChain, IDirect3DSurface9 *depthStencil, const Config *config)
: mDisplay(display), mSwapChain(swapChain), mDepthStencil(depthStencil), mConfig(config)
{
mBackBuffer = NULL;
mRenderTarget = NULL;
mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
mRenderBuffer = EGL_BACK_BUFFER;
mSwapBehavior = EGL_BUFFER_PRESERVED;
if (mSwapChain)
{
mSwapChain->AddRef();
mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
D3DSURFACE_DESC description;
mBackBuffer->GetDesc(&description);
mWidth = description.Width;
mHeight = description.Height;
IDirect3DDevice9 *device = display->getDevice();
HRESULT result = device->CreateRenderTarget(mWidth, mHeight, description.Format, description.MultiSampleType, description.MultiSampleQuality, FALSE, &mRenderTarget, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
error(EGL_BAD_ALLOC);
return;
}
ASSERT(SUCCEEDED(result));
}
}
Surface::~Surface()
{
if (mSwapChain)
{
mSwapChain->Release();
}
if (mBackBuffer)
{
mBackBuffer->Release();
}
if (mRenderTarget)
{
mRenderTarget->Release();
}
if (mDepthStencil)
{
mDepthStencil->Release();
}
}
HWND Surface::getWindowHandle()
{
if (mSwapChain)
{
D3DPRESENT_PARAMETERS presentParameters;
mSwapChain->GetPresentParameters(&presentParameters);
return presentParameters.hDeviceWindow;
}
return NULL;
}
void Surface::swap()
{
if (mSwapChain)
{
IDirect3DDevice9 *device = mDisplay->getDevice();
D3DSURFACE_DESC description;
mBackBuffer->GetDesc(&description);
// Copy the render target into a texture
IDirect3DTexture9 *texture;
HRESULT result = device->CreateTexture(mWidth, mHeight, 1, D3DUSAGE_RENDERTARGET, description.Format, D3DPOOL_DEFAULT, &texture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(EGL_BAD_ALLOC);
}
ASSERT(SUCCEEDED(result));
IDirect3DSurface9 *textureSurface;
texture->GetSurfaceLevel(0, &textureSurface);
mDisplay->endScene();
device->StretchRect(mRenderTarget, NULL, textureSurface, NULL, D3DTEXF_NONE);
// Disable all pipeline operations
device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
device->SetRenderState(D3DRS_ALPHATESTENABLE , FALSE);
device->SetRenderState(D3DRS_ALPHABLENDENABLE , FALSE);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
device->SetPixelShader(NULL);
device->SetVertexShader(NULL);
// Just sample the texture
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
device->SetTexture(0, texture);
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
device->SetRenderTarget(0, mBackBuffer);
// Render the texture upside down into the back buffer
float quad[4][6] = {{ 0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f},
{mWidth - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 1.0f, 1.0f},
{mWidth - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 1.0f, 0.0f},
{ 0 - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 0.0f, 0.0f}}; // x, y, z, rhw, u, v
mDisplay->startScene();
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
textureSurface->Release();
texture->Release();
mDisplay->endScene();
result = mSwapChain->Present(NULL, NULL, NULL, NULL, mDisplay->getPresentInterval(mConfig, false));
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
{
return error(EGL_BAD_ALLOC);
}
}
}
EGLint Surface::getWidth() const
{
return mWidth;
}
EGLint Surface::getHeight() const
{
return mHeight;
}
IDirect3DSurface9 *Surface::getRenderTarget()
{
if (mRenderTarget)
{
mRenderTarget->AddRef();
}
return mRenderTarget;
}
IDirect3DSurface9 *Surface::getDepthStencil()
{
if (mDepthStencil)
{
mDepthStencil->AddRef();
}
return mDepthStencil;
}
}