blob: a63eb455564409fc92942cfce295644ecd8d9e07 [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,
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000231 ConvertRenderbufferFormat(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};
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000283 presentParameters.AutoDepthStencilFormat = ConvertRenderbufferFormat(mConfig->mDepthStencilFormat);
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000284 presentParameters.BackBufferCount = 1;
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000285 presentParameters.BackBufferFormat = ConvertRenderbufferFormat(mConfig->mRenderTargetFormat);
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000286 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 {
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000337 result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
338 ConvertRenderbufferFormat(mConfig->mDepthStencilFormat), D3DMULTISAMPLE_NONE,
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000339 0, FALSE, &mDepthStencil, NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340
341 if (FAILED(result))
342 {
343 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
344
345 ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
346 release();
347
348 if(isDeviceLostError(result))
349 {
350 mDisplay->notifyDeviceLost();
351 return false;
352 }
353 else
354 {
355 return error(EGL_BAD_ALLOC, false);
356 }
357 }
358 }
359
apatrick@chromium.org0c71fd42012-08-10 18:08:47 +0000360 mWidth = backbufferWidth;
361 mHeight = backbufferHeight;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000362
363 mPresentIntervalDirty = false;
364 return true;
365}
366
367bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
368{
369 if (!mSwapChain)
370 {
371 return true;
372 }
373
374 if (x + width > mWidth)
375 {
376 width = mWidth - x;
377 }
378
379 if (y + height > mHeight)
380 {
381 height = mHeight - y;
382 }
383
384 if (width == 0 || height == 0)
385 {
386 return true;
387 }
388
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000389 renderer::Renderer *renderer = mDisplay->getRenderer();
390 IDirect3DDevice9 *device = renderer->getDevice();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000391
392 // Disable all pipeline operations
393 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
394 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
395 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
396 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
397 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
398 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
399 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
400 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
401 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
402 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
403 device->SetPixelShader(NULL);
404 device->SetVertexShader(NULL);
405
406 device->SetRenderTarget(0, mBackBuffer);
407 device->SetDepthStencilSurface(NULL);
408
409 device->SetTexture(0, mOffscreenTexture);
410 device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
411 device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
412 device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
413 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
414 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
415 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
416 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
417 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
418
419 D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
420 device->SetViewport(&viewport);
421
422 float x1 = x - 0.5f;
423 float y1 = (mHeight - y - height) - 0.5f;
424 float x2 = (x + width) - 0.5f;
425 float y2 = (mHeight - y) - 0.5f;
426
427 float u1 = x / float(mWidth);
428 float v1 = y / float(mHeight);
429 float u2 = (x + width) / float(mWidth);
430 float v2 = (y + height) / float(mHeight);
431
432 float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
433 {x2, y1, 0.0f, 1.0f, u2, v2},
434 {x2, y2, 0.0f, 1.0f, u2, v1},
435 {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
436
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000437 renderer->startScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000438 device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000439 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440
441 device->SetTexture(0, NULL);
442
443 RECT rect =
444 {
445 x, mHeight - y - height,
446 x + width, mHeight - y
447 };
448
449 HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
450
451 gl::Context *context = static_cast<gl::Context*>(glGetCurrentContext());
452 if (context)
453 {
454 context->markAllStateDirty();
455 }
456
457 if (isDeviceLostError(result))
458 {
459 mDisplay->notifyDeviceLost();
460 return false;
461 }
462
463 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
464 {
465 return error(EGL_BAD_ALLOC, false);
466 }
467
468 ASSERT(SUCCEEDED(result));
469
470 checkForOutOfDateSwapChain();
471
472 return true;
473}
474
475HWND Surface::getWindowHandle()
476{
477 return mWindow;
478}
479
480
481#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
482#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
483
484static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
485{
486 if (message == WM_SIZE)
487 {
488 Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
489 if(surf)
490 {
491 surf->checkForOutOfDateSwapChain();
492 }
493 }
494 WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
495 return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
496}
497
498void Surface::subclassWindow()
499{
500 if (!mWindow)
501 {
502 return;
503 }
504
505 DWORD processId;
506 DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
507 if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
508 {
509 return;
510 }
511
512 SetLastError(0);
513 LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
514 if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
515 {
516 mWindowSubclassed = false;
517 return;
518 }
519
520 SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
521 SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
522 mWindowSubclassed = true;
523}
524
525void Surface::unsubclassWindow()
526{
527 if(!mWindowSubclassed)
528 {
529 return;
530 }
531
532 // un-subclass
533 LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
534
535 // Check the windowproc is still SurfaceWindowProc.
536 // If this assert fails, then it is likely the application has subclassed the
537 // hwnd as well and did not unsubclass before destroying its EGL context. The
538 // application should be modified to either subclass before initializing the
539 // EGL context, or to unsubclass before destroying the EGL context.
540 if(parentWndFunc)
541 {
542 LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
543 ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
544 }
545
546 RemoveProp(mWindow, kSurfaceProperty);
547 RemoveProp(mWindow, kParentWndProc);
548 mWindowSubclassed = false;
549}
550
551bool Surface::checkForOutOfDateSwapChain()
552{
553 RECT client;
554 if (!GetClientRect(getWindowHandle(), &client))
555 {
556 ASSERT(false);
557 return false;
558 }
559
560 // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
561 int clientWidth = client.right - client.left;
562 int clientHeight = client.bottom - client.top;
563 bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
564
565 if (sizeDirty || mPresentIntervalDirty)
566 {
567 resetSwapChain(clientWidth, clientHeight);
568 if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
569 {
570 glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
571 }
572
573 return true;
574 }
575 return false;
576}
577
578DWORD Surface::convertInterval(EGLint interval)
579{
580 switch(interval)
581 {
582 case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
583 case 1: return D3DPRESENT_INTERVAL_ONE;
584 case 2: return D3DPRESENT_INTERVAL_TWO;
585 case 3: return D3DPRESENT_INTERVAL_THREE;
586 case 4: return D3DPRESENT_INTERVAL_FOUR;
587 default: UNREACHABLE();
588 }
589
590 return D3DPRESENT_INTERVAL_DEFAULT;
591}
592
593bool Surface::swap()
594{
595 return swapRect(0, 0, mWidth, mHeight);
596}
597
598bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
599{
600 if (!mPostSubBufferSupported)
601 {
602 // Spec is not clear about how this should be handled.
603 return true;
604 }
605
606 return swapRect(x, y, width, height);
607}
608
609EGLint Surface::getWidth() const
610{
611 return mWidth;
612}
613
614EGLint Surface::getHeight() const
615{
616 return mHeight;
617}
618
619EGLint Surface::isPostSubBufferSupported() const
620{
621 return mPostSubBufferSupported;
622}
623
624// Increments refcount on surface.
625// caller must Release() the returned surface
626IDirect3DSurface9 *Surface::getRenderTarget()
627{
628 if (mRenderTarget)
629 {
630 mRenderTarget->AddRef();
631 }
632
633 return mRenderTarget;
634}
635
636// Increments refcount on surface.
637// caller must Release() the returned surface
638IDirect3DSurface9 *Surface::getDepthStencil()
639{
640 if (mDepthStencil)
641 {
642 mDepthStencil->AddRef();
643 }
644
645 return mDepthStencil;
646}
647
648IDirect3DTexture9 *Surface::getOffscreenTexture()
649{
650 if (mOffscreenTexture)
651 {
652 mOffscreenTexture->AddRef();
653 }
654
655 return mOffscreenTexture;
656}
657
658void Surface::setSwapInterval(EGLint interval)
659{
660 if (mSwapInterval == interval)
661 {
662 return;
663 }
664
665 mSwapInterval = interval;
666 mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
667 mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
668
669 mPresentInterval = convertInterval(mSwapInterval);
670 mPresentIntervalDirty = true;
671}
672
673EGLenum Surface::getTextureFormat() const
674{
675 return mTextureFormat;
676}
677
678EGLenum Surface::getTextureTarget() const
679{
680 return mTextureTarget;
681}
682
683void Surface::setBoundTexture(gl::Texture2D *texture)
684{
685 mTexture = texture;
686}
687
688gl::Texture2D *Surface::getBoundTexture() const
689{
690 return mTexture;
691}
692
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000693EGLenum Surface::getFormat() const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694{
695 return mConfig->mRenderTargetFormat;
696}
697}