blob: 57014e4f09440f9dade006b0fedb521a3d5889e7 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Surface.cpp: Implements the egl::Surface class, representing a drawing surface
8// such as the client area of a window, including any back buffers.
9// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
10
11#include <tchar.h>
12
13#include "libEGL/Surface.h"
14
15#include "common/debug.h"
16#include "libGLESv2/Texture.h"
17
18#include "libEGL/main.h"
19#include "libEGL/Display.h"
20
21#include <dwmapi.h>
22
23namespace egl
24{
25
daniel@transgaming.come7b2f052012-10-31 18:38:32 +000026// D3D9_REMOVE - Temporary duplication of this conversion function until remainder of d3d types are stripped
27D3DFORMAT ConvertRenderbufferFormat(GLenum format)
28{
29 switch (format)
30 {
31 case GL_NONE: return D3DFMT_NULL;
32 case GL_RGBA4:
33 case GL_RGB5_A1:
34 case GL_RGBA8_OES: return D3DFMT_A8R8G8B8;
35 case GL_RGB565: return D3DFMT_R5G6B5;
36 case GL_RGB8_OES: return D3DFMT_X8R8G8B8;
37 case GL_DEPTH_COMPONENT16:
38 case GL_STENCIL_INDEX8:
39 case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
40 default: UNREACHABLE(); return D3DFMT_A8R8G8B8;
41 }
42}
43
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000044Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported)
45 : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported)
46{
47 mSwapChain = NULL;
48 mBackBuffer = NULL;
49 mDepthStencil = NULL;
50 mRenderTarget = NULL;
51 mOffscreenTexture = NULL;
52 mShareHandle = NULL;
53 mTexture = NULL;
54 mTextureFormat = EGL_NO_TEXTURE;
55 mTextureTarget = EGL_NO_TEXTURE;
56
57 mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
58 mRenderBuffer = EGL_BACK_BUFFER;
59 mSwapBehavior = EGL_BUFFER_PRESERVED;
60 mSwapInterval = -1;
61 setSwapInterval(1);
62
63 subclassWindow();
64}
65
66Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType)
67 : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE)
68{
69 mSwapChain = NULL;
70 mBackBuffer = NULL;
71 mDepthStencil = NULL;
72 mRenderTarget = NULL;
73 mOffscreenTexture = NULL;
74 mWindowSubclassed = false;
75 mTexture = NULL;
76 mTextureFormat = textureFormat;
77 mTextureTarget = textureType;
78
79 mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
80 mRenderBuffer = EGL_BACK_BUFFER;
81 mSwapBehavior = EGL_BUFFER_PRESERVED;
82 mSwapInterval = -1;
83 setSwapInterval(1);
84}
85
86Surface::~Surface()
87{
88 unsubclassWindow();
89 release();
90}
91
92bool Surface::initialize()
93{
94 ASSERT(!mSwapChain && !mOffscreenTexture && !mDepthStencil);
95
96 if (!resetSwapChain())
97 return false;
98
99 // Modify present parameters for this window, if we are composited,
100 // to minimize the amount of queuing done by DWM between our calls to
101 // present and the actual screen.
102 if (mWindow && (getComparableOSVersion() >= versionWindowsVista)) {
103 BOOL isComposited;
104 HRESULT result = DwmIsCompositionEnabled(&isComposited);
105 if (SUCCEEDED(result) && isComposited) {
106 DWM_PRESENT_PARAMETERS presentParams;
107 memset(&presentParams, 0, sizeof(presentParams));
108 presentParams.cbSize = sizeof(DWM_PRESENT_PARAMETERS);
109 presentParams.cBuffer = 2;
110
111 result = DwmSetPresentParameters(mWindow, &presentParams);
112 if (FAILED(result))
113 ERR("Unable to set present parameters: 0x%08X", result);
114 }
115 }
116
117 return true;
118}
119
120void Surface::release()
121{
122 if (mSwapChain)
123 {
124 mSwapChain->Release();
125 mSwapChain = NULL;
126 }
127
128 if (mBackBuffer)
129 {
130 mBackBuffer->Release();
131 mBackBuffer = NULL;
132 }
133
134 if (mDepthStencil)
135 {
136 mDepthStencil->Release();
137 mDepthStencil = NULL;
138 }
139
140 if (mRenderTarget)
141 {
142 mRenderTarget->Release();
143 mRenderTarget = NULL;
144 }
145
146 if (mOffscreenTexture)
147 {
148 mOffscreenTexture->Release();
149 mOffscreenTexture = NULL;
150 }
151
152 if (mTexture)
153 {
154 mTexture->releaseTexImage();
155 mTexture = NULL;
156 }
157
158 mShareHandle = NULL;
159}
160
161bool Surface::resetSwapChain()
162{
163 if (!mWindow)
164 {
165 return resetSwapChain(mWidth, mHeight);
166 }
167
168 RECT windowRect;
169 if (!GetClientRect(getWindowHandle(), &windowRect))
170 {
171 ASSERT(false);
172
173 ERR("Could not retrieve the window dimensions");
174 return false;
175 }
176
177 return resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
178}
179
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000180// D3D9_REPLACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000181bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
182{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000183 renderer::Renderer *renderer = mDisplay->getRenderer();
184 IDirect3DDevice9 *device = renderer->getDevice();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000185
186 if (device == NULL)
187 {
188 return false;
189 }
190
191 // Evict all non-render target textures to system memory and release all resources
192 // before reallocating them to free up as much video memory as possible.
193 device->EvictManagedResources();
194
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000195 HRESULT result;
196
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000197 // Release specific resources to free up memory for the new render target, while the
198 // old render target still exists for the purpose of preserving its contents.
199 if (mSwapChain)
200 {
201 mSwapChain->Release();
202 mSwapChain = NULL;
203 }
204
205 if (mBackBuffer)
206 {
207 mBackBuffer->Release();
208 mBackBuffer = NULL;
209 }
210
211 if (mOffscreenTexture)
212 {
213 mOffscreenTexture->Release();
214 mOffscreenTexture = NULL;
215 }
216
217 if (mDepthStencil)
218 {
219 mDepthStencil->Release();
220 mDepthStencil = NULL;
221 }
222
223 mShareHandle = NULL;
224 HANDLE *pShareHandle = NULL;
daniel@transgaming.com313e3922012-10-31 17:52:39 +0000225 if (!mWindow && renderer->getShareHandleSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000226 {
227 pShareHandle = &mShareHandle;
228 }
229
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000230 result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
231 mConfig->mRenderTargetFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle);
daniel@transgaming.come7b2f052012-10-31 18:38:32 +0000232
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233 if (FAILED(result))
234 {
235 ERR("Could not create offscreen texture: %08lX", result);
236 release();
237
238 if(isDeviceLostError(result))
239 {
240 mDisplay->notifyDeviceLost();
241 return false;
242 }
243 else
244 {
245 return error(EGL_BAD_ALLOC, false);
246 }
247 }
248
249 IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
250
251 result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
252 ASSERT(SUCCEEDED(result));
253
254 if (oldRenderTarget)
255 {
256 RECT rect =
257 {
258 0, 0,
259 mWidth, mHeight
260 };
261
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000262 if (rect.right > static_cast<LONG>(backbufferWidth))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263 {
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000264 rect.right = backbufferWidth;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265 }
266
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000267 if (rect.bottom > static_cast<LONG>(backbufferHeight))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268 {
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000269 rect.bottom = backbufferHeight;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000270 }
271
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000272 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273
274 result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
275 ASSERT(SUCCEEDED(result));
276
277 oldRenderTarget->Release();
278 }
279
280 if (mWindow)
281 {
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000282 D3DPRESENT_PARAMETERS presentParameters = {0};
283 presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat;
284 presentParameters.BackBufferCount = 1;
285 presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat;
286 presentParameters.EnableAutoDepthStencil = FALSE;
287 presentParameters.Flags = 0;
288 presentParameters.hDeviceWindow = getWindowHandle();
289 presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
290 presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
291 presentParameters.PresentationInterval = mPresentInterval;
292 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
293 presentParameters.Windowed = TRUE;
294 presentParameters.BackBufferWidth = backbufferWidth;
295 presentParameters.BackBufferHeight = backbufferHeight;
296
297 // http://crbug.com/140239
apatrick@chromium.org85e44192012-08-17 20:58:01 +0000298 // http://crbug.com/143434
299 //
300 // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
301 // when using the integrated Intel. This rounds the width up rather than down.
302 //
303 // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
304 // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000305 D3DADAPTER_IDENTIFIER9* adapterIdentifier = renderer->getAdapterIdentifier();
apatrick@chromium.org85e44192012-08-17 20:58:01 +0000306 if (adapterIdentifier->VendorId == VENDOR_ID_INTEL)
307 {
308 presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
309 }
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000310
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000311 result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
312
313 if (FAILED(result))
314 {
315 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
316
317 ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
318 release();
319
320 if(isDeviceLostError(result))
321 {
322 mDisplay->notifyDeviceLost();
323 return false;
324 }
325 else
326 {
327 return error(EGL_BAD_ALLOC, false);
328 }
329 }
330
331 result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
332 ASSERT(SUCCEEDED(result));
333 }
334
335 if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN)
336 {
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000337 result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, mConfig->mDepthStencilFormat, D3DMULTISAMPLE_NONE,
338 0, FALSE, &mDepthStencil, NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000339
340 if (FAILED(result))
341 {
342 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
343
344 ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
345 release();
346
347 if(isDeviceLostError(result))
348 {
349 mDisplay->notifyDeviceLost();
350 return false;
351 }
352 else
353 {
354 return error(EGL_BAD_ALLOC, false);
355 }
356 }
357 }
358
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000359 mWidth = backbufferWidth;
360 mHeight = backbufferHeight;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000361
362 mPresentIntervalDirty = false;
363 return true;
364}
365
366bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
367{
368 if (!mSwapChain)
369 {
370 return true;
371 }
372
373 if (x + width > mWidth)
374 {
375 width = mWidth - x;
376 }
377
378 if (y + height > mHeight)
379 {
380 height = mHeight - y;
381 }
382
383 if (width == 0 || height == 0)
384 {
385 return true;
386 }
387
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000388 renderer::Renderer *renderer = mDisplay->getRenderer();
389 IDirect3DDevice9 *device = renderer->getDevice();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000390
391 // Disable all pipeline operations
392 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
393 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
394 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
395 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
396 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
397 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
398 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
399 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
400 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
401 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
402 device->SetPixelShader(NULL);
403 device->SetVertexShader(NULL);
404
405 device->SetRenderTarget(0, mBackBuffer);
406 device->SetDepthStencilSurface(NULL);
407
408 device->SetTexture(0, mOffscreenTexture);
409 device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
410 device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
411 device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
412 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
413 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
414 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
415 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
416 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
417
418 D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
419 device->SetViewport(&viewport);
420
421 float x1 = x - 0.5f;
422 float y1 = (mHeight - y - height) - 0.5f;
423 float x2 = (x + width) - 0.5f;
424 float y2 = (mHeight - y) - 0.5f;
425
426 float u1 = x / float(mWidth);
427 float v1 = y / float(mHeight);
428 float u2 = (x + width) / float(mWidth);
429 float v2 = (y + height) / float(mHeight);
430
431 float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
432 {x2, y1, 0.0f, 1.0f, u2, v2},
433 {x2, y2, 0.0f, 1.0f, u2, v1},
434 {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
435
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000436 renderer->startScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000437 device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000438 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439
440 device->SetTexture(0, NULL);
441
442 RECT rect =
443 {
444 x, mHeight - y - height,
445 x + width, mHeight - y
446 };
447
448 HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
449
450 gl::Context *context = static_cast<gl::Context*>(glGetCurrentContext());
451 if (context)
452 {
453 context->markAllStateDirty();
454 }
455
456 if (isDeviceLostError(result))
457 {
458 mDisplay->notifyDeviceLost();
459 return false;
460 }
461
462 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
463 {
464 return error(EGL_BAD_ALLOC, false);
465 }
466
467 ASSERT(SUCCEEDED(result));
468
469 checkForOutOfDateSwapChain();
470
471 return true;
472}
473
474HWND Surface::getWindowHandle()
475{
476 return mWindow;
477}
478
479
480#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
481#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
482
483static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
484{
485 if (message == WM_SIZE)
486 {
487 Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
488 if(surf)
489 {
490 surf->checkForOutOfDateSwapChain();
491 }
492 }
493 WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
494 return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
495}
496
497void Surface::subclassWindow()
498{
499 if (!mWindow)
500 {
501 return;
502 }
503
504 DWORD processId;
505 DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
506 if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
507 {
508 return;
509 }
510
511 SetLastError(0);
512 LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
513 if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
514 {
515 mWindowSubclassed = false;
516 return;
517 }
518
519 SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
520 SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
521 mWindowSubclassed = true;
522}
523
524void Surface::unsubclassWindow()
525{
526 if(!mWindowSubclassed)
527 {
528 return;
529 }
530
531 // un-subclass
532 LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
533
534 // Check the windowproc is still SurfaceWindowProc.
535 // If this assert fails, then it is likely the application has subclassed the
536 // hwnd as well and did not unsubclass before destroying its EGL context. The
537 // application should be modified to either subclass before initializing the
538 // EGL context, or to unsubclass before destroying the EGL context.
539 if(parentWndFunc)
540 {
541 LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
542 ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
543 }
544
545 RemoveProp(mWindow, kSurfaceProperty);
546 RemoveProp(mWindow, kParentWndProc);
547 mWindowSubclassed = false;
548}
549
550bool Surface::checkForOutOfDateSwapChain()
551{
552 RECT client;
553 if (!GetClientRect(getWindowHandle(), &client))
554 {
555 ASSERT(false);
556 return false;
557 }
558
559 // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
560 int clientWidth = client.right - client.left;
561 int clientHeight = client.bottom - client.top;
562 bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
563
564 if (sizeDirty || mPresentIntervalDirty)
565 {
566 resetSwapChain(clientWidth, clientHeight);
567 if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
568 {
569 glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
570 }
571
572 return true;
573 }
574 return false;
575}
576
577DWORD Surface::convertInterval(EGLint interval)
578{
579 switch(interval)
580 {
581 case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
582 case 1: return D3DPRESENT_INTERVAL_ONE;
583 case 2: return D3DPRESENT_INTERVAL_TWO;
584 case 3: return D3DPRESENT_INTERVAL_THREE;
585 case 4: return D3DPRESENT_INTERVAL_FOUR;
586 default: UNREACHABLE();
587 }
588
589 return D3DPRESENT_INTERVAL_DEFAULT;
590}
591
592bool Surface::swap()
593{
594 return swapRect(0, 0, mWidth, mHeight);
595}
596
597bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
598{
599 if (!mPostSubBufferSupported)
600 {
601 // Spec is not clear about how this should be handled.
602 return true;
603 }
604
605 return swapRect(x, y, width, height);
606}
607
608EGLint Surface::getWidth() const
609{
610 return mWidth;
611}
612
613EGLint Surface::getHeight() const
614{
615 return mHeight;
616}
617
618EGLint Surface::isPostSubBufferSupported() const
619{
620 return mPostSubBufferSupported;
621}
622
623// Increments refcount on surface.
624// caller must Release() the returned surface
625IDirect3DSurface9 *Surface::getRenderTarget()
626{
627 if (mRenderTarget)
628 {
629 mRenderTarget->AddRef();
630 }
631
632 return mRenderTarget;
633}
634
635// Increments refcount on surface.
636// caller must Release() the returned surface
637IDirect3DSurface9 *Surface::getDepthStencil()
638{
639 if (mDepthStencil)
640 {
641 mDepthStencil->AddRef();
642 }
643
644 return mDepthStencil;
645}
646
647IDirect3DTexture9 *Surface::getOffscreenTexture()
648{
649 if (mOffscreenTexture)
650 {
651 mOffscreenTexture->AddRef();
652 }
653
654 return mOffscreenTexture;
655}
656
657void Surface::setSwapInterval(EGLint interval)
658{
659 if (mSwapInterval == interval)
660 {
661 return;
662 }
663
664 mSwapInterval = interval;
665 mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
666 mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
667
668 mPresentInterval = convertInterval(mSwapInterval);
669 mPresentIntervalDirty = true;
670}
671
672EGLenum Surface::getTextureFormat() const
673{
674 return mTextureFormat;
675}
676
677EGLenum Surface::getTextureTarget() const
678{
679 return mTextureTarget;
680}
681
682void Surface::setBoundTexture(gl::Texture2D *texture)
683{
684 mTexture = texture;
685}
686
687gl::Texture2D *Surface::getBoundTexture() const
688{
689 return mTexture;
690}
691
692D3DFORMAT Surface::getFormat() const
693{
694 return mConfig->mRenderTargetFormat;
695}
696}