SurfaceD3D.cpp (14769B)
1 // 2 // Copyright 2014 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 // SurfaceD3D.cpp: D3D implementation of an EGL surface 8 9 #include "libANGLE/renderer/d3d/SurfaceD3D.h" 10 11 #include "libANGLE/Context.h" 12 #include "libANGLE/Display.h" 13 #include "libANGLE/Surface.h" 14 #include "libANGLE/renderer/Format.h" 15 #include "libANGLE/renderer/d3d/DisplayD3D.h" 16 #include "libANGLE/renderer/d3d/RenderTargetD3D.h" 17 #include "libANGLE/renderer/d3d/RendererD3D.h" 18 #include "libANGLE/renderer/d3d/SwapChainD3D.h" 19 20 #include <EGL/eglext.h> 21 #include <tchar.h> 22 #include <algorithm> 23 24 namespace rx 25 { 26 27 SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state, 28 RendererD3D *renderer, 29 egl::Display *display, 30 EGLNativeWindowType window, 31 EGLenum buftype, 32 EGLClientBuffer clientBuffer, 33 const egl::AttributeMap &attribs) 34 : SurfaceImpl(state), 35 mRenderer(renderer), 36 mDisplay(display), 37 mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE), 38 mFixedWidth(0), 39 mFixedHeight(0), 40 mOrientation(static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))), 41 mRenderTargetFormat(state.config->renderTargetFormat), 42 mDepthStencilFormat(state.config->depthStencilFormat), 43 mColorFormat(nullptr), 44 mSwapChain(nullptr), 45 mSwapIntervalDirty(true), 46 mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)), 47 mWidth(static_cast<EGLint>(attribs.get(EGL_WIDTH, 0))), 48 mHeight(static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0))), 49 mSwapInterval(1), 50 mShareHandle(0), 51 mD3DTexture(nullptr), 52 mBuftype(buftype) 53 { 54 if (window != nullptr && !mFixedSize) 55 { 56 mWidth = -1; 57 mHeight = -1; 58 } 59 60 if (mFixedSize) 61 { 62 mFixedWidth = mWidth; 63 mFixedHeight = mHeight; 64 } 65 66 switch (buftype) 67 { 68 case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: 69 mShareHandle = static_cast<HANDLE>(clientBuffer); 70 break; 71 72 case EGL_D3D_TEXTURE_ANGLE: 73 mD3DTexture = static_cast<IUnknown *>(clientBuffer); 74 ASSERT(mD3DTexture != nullptr); 75 mD3DTexture->AddRef(); 76 break; 77 78 default: 79 break; 80 } 81 } 82 83 SurfaceD3D::~SurfaceD3D() 84 { 85 releaseSwapChain(); 86 SafeDelete(mNativeWindow); 87 SafeRelease(mD3DTexture); 88 } 89 90 void SurfaceD3D::releaseSwapChain() 91 { 92 SafeDelete(mSwapChain); 93 } 94 95 egl::Error SurfaceD3D::initialize(const egl::Display *display) 96 { 97 if (mNativeWindow->getNativeWindow()) 98 { 99 if (!mNativeWindow->initialize()) 100 { 101 return egl::EglBadSurface(); 102 } 103 } 104 105 if (mBuftype == EGL_D3D_TEXTURE_ANGLE) 106 { 107 ANGLE_TRY(mRenderer->getD3DTextureInfo(mState.config, mD3DTexture, mState.attributes, 108 &mFixedWidth, &mFixedHeight, nullptr, nullptr, 109 &mColorFormat, nullptr)); 110 if (mState.attributes.contains(EGL_GL_COLORSPACE)) 111 { 112 if (mColorFormat->id != angle::FormatID::R8G8B8A8_TYPELESS && 113 mColorFormat->id != angle::FormatID::B8G8R8A8_TYPELESS) 114 { 115 return egl::EglBadMatch() 116 << "EGL_GL_COLORSPACE may only be specified for TYPELESS textures"; 117 } 118 } 119 if (mColorFormat->id == angle::FormatID::R8G8B8A8_TYPELESS) 120 { 121 EGLAttrib colorspace = 122 mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR); 123 if (colorspace == EGL_GL_COLORSPACE_SRGB) 124 { 125 mColorFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_TYPELESS_SRGB); 126 } 127 } 128 if (mColorFormat->id == angle::FormatID::B8G8R8A8_TYPELESS) 129 { 130 EGLAttrib colorspace = 131 mState.attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR); 132 if (colorspace == EGL_GL_COLORSPACE_SRGB) 133 { 134 mColorFormat = &angle::Format::Get(angle::FormatID::B8G8R8A8_TYPELESS_SRGB); 135 } 136 } 137 mRenderTargetFormat = mColorFormat->fboImplementationInternalFormat; 138 } 139 140 ANGLE_TRY(resetSwapChain(display)); 141 return egl::NoError(); 142 } 143 144 egl::Error SurfaceD3D::bindTexImage(const gl::Context *, gl::Texture *, EGLint) 145 { 146 return egl::NoError(); 147 } 148 149 egl::Error SurfaceD3D::releaseTexImage(const gl::Context *, EGLint) 150 { 151 return egl::NoError(); 152 } 153 154 egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) 155 { 156 if (!mState.directComposition) 157 { 158 return egl::EglBadSurface() 159 << "getSyncValues: surface requires Direct Composition to be enabled"; 160 } 161 162 return mSwapChain->getSyncValues(ust, msc, sbc); 163 } 164 165 egl::Error SurfaceD3D::getMscRate(EGLint *numerator, EGLint *denominator) 166 { 167 UNIMPLEMENTED(); 168 return egl::EglBadAccess(); 169 } 170 171 egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display) 172 { 173 ASSERT(!mSwapChain); 174 175 int width; 176 int height; 177 178 if (!mFixedSize) 179 { 180 RECT windowRect; 181 if (!mNativeWindow->getClientRect(&windowRect)) 182 { 183 ASSERT(false); 184 185 return egl::EglBadSurface() << "Could not retrieve the window dimensions"; 186 } 187 188 width = windowRect.right - windowRect.left; 189 height = windowRect.bottom - windowRect.top; 190 } 191 else 192 { 193 // non-window surface - size is determined at creation 194 width = mFixedWidth; 195 height = mFixedHeight; 196 } 197 198 mSwapChain = 199 mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat, 200 mDepthStencilFormat, mOrientation, mState.config->samples); 201 if (!mSwapChain) 202 { 203 return egl::EglBadAlloc(); 204 } 205 206 // This is a bit risky to pass the proxy context here, but it can happen at almost any time. 207 DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(display); 208 egl::Error error = resetSwapChain(displayD3D, width, height); 209 if (error.isError()) 210 { 211 SafeDelete(mSwapChain); 212 return error; 213 } 214 215 return egl::NoError(); 216 } 217 218 egl::Error SurfaceD3D::resizeSwapChain(DisplayD3D *displayD3D, 219 int backbufferWidth, 220 int backbufferHeight) 221 { 222 ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); 223 ASSERT(mSwapChain); 224 225 EGLint status = 226 mSwapChain->resize(displayD3D, std::max(1, backbufferWidth), std::max(1, backbufferHeight)); 227 228 if (status == EGL_CONTEXT_LOST) 229 { 230 mDisplay->notifyDeviceLost(); 231 return egl::Error(status); 232 } 233 else if (status != EGL_SUCCESS) 234 { 235 return egl::Error(status); 236 } 237 238 mWidth = backbufferWidth; 239 mHeight = backbufferHeight; 240 241 return egl::NoError(); 242 } 243 244 egl::Error SurfaceD3D::resetSwapChain(DisplayD3D *displayD3D, 245 int backbufferWidth, 246 int backbufferHeight) 247 { 248 ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); 249 ASSERT(mSwapChain); 250 251 EGLint status = mSwapChain->reset(displayD3D, std::max(1, backbufferWidth), 252 std::max(1, backbufferHeight), mSwapInterval); 253 254 if (status == EGL_CONTEXT_LOST) 255 { 256 mRenderer->notifyDeviceLost(); 257 return egl::Error(status); 258 } 259 else if (status != EGL_SUCCESS) 260 { 261 return egl::Error(status); 262 } 263 264 mWidth = backbufferWidth; 265 mHeight = backbufferHeight; 266 mSwapIntervalDirty = false; 267 268 return egl::NoError(); 269 } 270 271 egl::Error SurfaceD3D::swapRect(DisplayD3D *displayD3D, 272 EGLint x, 273 EGLint y, 274 EGLint width, 275 EGLint height) 276 { 277 if (!mSwapChain) 278 { 279 return egl::NoError(); 280 } 281 282 if (x + width > mWidth) 283 { 284 width = mWidth - x; 285 } 286 287 if (y + height > mHeight) 288 { 289 height = mHeight - y; 290 } 291 292 if (width != 0 && height != 0) 293 { 294 EGLint status = mSwapChain->swapRect(displayD3D, x, y, width, height); 295 296 if (status == EGL_CONTEXT_LOST) 297 { 298 mRenderer->notifyDeviceLost(); 299 return egl::Error(status); 300 } 301 else if (status != EGL_SUCCESS) 302 { 303 return egl::Error(status); 304 } 305 } 306 307 ANGLE_TRY(checkForOutOfDateSwapChain(displayD3D)); 308 309 return egl::NoError(); 310 } 311 312 egl::Error SurfaceD3D::checkForOutOfDateSwapChain(DisplayD3D *displayD3D) 313 { 314 RECT client; 315 int clientWidth = getWidth(); 316 int clientHeight = getHeight(); 317 bool sizeDirty = false; 318 if (!mFixedSize && !mNativeWindow->isIconic()) 319 { 320 // The window is automatically resized to 150x22 when it's minimized, but the swapchain 321 // shouldn't be resized because that's not a useful size to render to. 322 if (!mNativeWindow->getClientRect(&client)) 323 { 324 UNREACHABLE(); 325 return egl::NoError(); 326 } 327 328 // Grow the buffer now, if the window has grown. We need to grow now to avoid losing 329 // information. 330 clientWidth = client.right - client.left; 331 clientHeight = client.bottom - client.top; 332 sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); 333 } 334 else if (mFixedSize) 335 { 336 clientWidth = mFixedWidth; 337 clientHeight = mFixedHeight; 338 sizeDirty = mFixedWidth != getWidth() || mFixedHeight != getHeight(); 339 } 340 341 if (mSwapIntervalDirty) 342 { 343 ANGLE_TRY(resetSwapChain(displayD3D, clientWidth, clientHeight)); 344 } 345 else if (sizeDirty) 346 { 347 ANGLE_TRY(resizeSwapChain(displayD3D, clientWidth, clientHeight)); 348 } 349 350 return egl::NoError(); 351 } 352 353 egl::Error SurfaceD3D::swap(const gl::Context *context) 354 { 355 DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay()); 356 return swapRect(displayD3D, 0, 0, mWidth, mHeight); 357 } 358 359 egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context, 360 EGLint x, 361 EGLint y, 362 EGLint width, 363 EGLint height) 364 { 365 DisplayD3D *displayD3D = GetImplAs<DisplayD3D>(context->getDisplay()); 366 return swapRect(displayD3D, x, y, width, height); 367 } 368 369 rx::SwapChainD3D *SurfaceD3D::getSwapChain() const 370 { 371 return mSwapChain; 372 } 373 374 void SurfaceD3D::setSwapInterval(EGLint interval) 375 { 376 if (mSwapInterval == interval) 377 { 378 return; 379 } 380 381 mSwapInterval = interval; 382 mSwapIntervalDirty = true; 383 } 384 385 void SurfaceD3D::setFixedWidth(EGLint width) 386 { 387 mFixedWidth = width; 388 } 389 390 void SurfaceD3D::setFixedHeight(EGLint height) 391 { 392 mFixedHeight = height; 393 } 394 395 EGLint SurfaceD3D::getWidth() const 396 { 397 return mWidth; 398 } 399 400 EGLint SurfaceD3D::getHeight() const 401 { 402 return mHeight; 403 } 404 405 EGLint SurfaceD3D::isPostSubBufferSupported() const 406 { 407 // post sub buffer is always possible on D3D surfaces 408 return EGL_TRUE; 409 } 410 411 EGLint SurfaceD3D::getSwapBehavior() const 412 { 413 return EGL_BUFFER_PRESERVED; 414 } 415 416 egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) 417 { 418 if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) 419 { 420 *value = mSwapChain->getShareHandle(); 421 } 422 else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE) 423 { 424 *value = mSwapChain->getKeyedMutex(); 425 } 426 else 427 UNREACHABLE(); 428 429 return egl::NoError(); 430 } 431 432 const angle::Format *SurfaceD3D::getD3DTextureColorFormat() const 433 { 434 return mColorFormat; 435 } 436 437 egl::Error SurfaceD3D::attachToFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer) 438 { 439 return egl::NoError(); 440 } 441 442 egl::Error SurfaceD3D::detachFromFramebuffer(const gl::Context *context, 443 gl::Framebuffer *framebuffer) 444 { 445 return egl::NoError(); 446 } 447 448 angle::Result SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context, 449 GLenum binding, 450 const gl::ImageIndex &imageIndex, 451 GLsizei samples, 452 FramebufferAttachmentRenderTarget **rtOut) 453 { 454 if (binding == GL_BACK) 455 { 456 *rtOut = mSwapChain->getColorRenderTarget(); 457 } 458 else 459 { 460 *rtOut = mSwapChain->getDepthStencilRenderTarget(); 461 } 462 return angle::Result::Continue; 463 } 464 465 angle::Result SurfaceD3D::initializeContents(const gl::Context *context, 466 GLenum binding, 467 const gl::ImageIndex &imageIndex) 468 { 469 switch (binding) 470 { 471 case GL_BACK: 472 ASSERT(mState.config->renderTargetFormat != GL_NONE); 473 ANGLE_TRY(mRenderer->initRenderTarget(context, mSwapChain->getColorRenderTarget())); 474 break; 475 476 case GL_DEPTH: 477 case GL_STENCIL: 478 ASSERT(mState.config->depthStencilFormat != GL_NONE); 479 ANGLE_TRY( 480 mRenderer->initRenderTarget(context, mSwapChain->getDepthStencilRenderTarget())); 481 break; 482 483 default: 484 UNREACHABLE(); 485 break; 486 } 487 return angle::Result::Continue; 488 } 489 490 WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state, 491 RendererD3D *renderer, 492 egl::Display *display, 493 EGLNativeWindowType window, 494 const egl::AttributeMap &attribs) 495 : SurfaceD3D(state, renderer, display, window, 0, static_cast<EGLClientBuffer>(0), attribs) 496 {} 497 498 WindowSurfaceD3D::~WindowSurfaceD3D() {} 499 500 PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state, 501 RendererD3D *renderer, 502 egl::Display *display, 503 EGLenum buftype, 504 EGLClientBuffer clientBuffer, 505 const egl::AttributeMap &attribs) 506 : SurfaceD3D(state, 507 renderer, 508 display, 509 static_cast<EGLNativeWindowType>(0), 510 buftype, 511 clientBuffer, 512 attribs) 513 {} 514 515 PbufferSurfaceD3D::~PbufferSurfaceD3D() {} 516 517 } // namespace rx