Framebuffer9.cpp (15268B)
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 // Framebuffer9.cpp: Implements the Framebuffer9 class. 8 9 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" 10 11 #include "libANGLE/Context.h" 12 #include "libANGLE/Framebuffer.h" 13 #include "libANGLE/FramebufferAttachment.h" 14 #include "libANGLE/Texture.h" 15 #include "libANGLE/formatutils.h" 16 #include "libANGLE/renderer/ContextImpl.h" 17 #include "libANGLE/renderer/d3d/TextureD3D.h" 18 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" 19 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" 20 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" 21 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" 22 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" 23 #include "libANGLE/renderer/renderer_utils.h" 24 25 namespace rx 26 { 27 Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer) 28 : FramebufferD3D(data, renderer), mRenderer(renderer) 29 { 30 ASSERT(mRenderer != nullptr); 31 } 32 33 Framebuffer9::~Framebuffer9() {} 34 35 angle::Result Framebuffer9::discard(const gl::Context *context, 36 size_t count, 37 const GLenum *attachments) 38 { 39 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 40 return angle::Result::Stop; 41 } 42 43 angle::Result Framebuffer9::invalidate(const gl::Context *context, 44 size_t count, 45 const GLenum *attachments) 46 { 47 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 48 return angle::Result::Stop; 49 } 50 51 angle::Result Framebuffer9::invalidateSub(const gl::Context *context, 52 size_t count, 53 const GLenum *attachments, 54 const gl::Rectangle &area) 55 { 56 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 57 return angle::Result::Stop; 58 } 59 60 angle::Result Framebuffer9::clearImpl(const gl::Context *context, 61 const ClearParameters &clearParams) 62 { 63 ANGLE_TRY(mRenderer->applyRenderTarget(context, mRenderTargetCache.getColors()[0], 64 mRenderTargetCache.getDepthStencil())); 65 66 const gl::State &glState = context->getState(); 67 float nearZ = glState.getNearPlane(); 68 float farZ = glState.getFarPlane(); 69 mRenderer->setViewport(glState.getViewport(), nearZ, farZ, gl::PrimitiveMode::Triangles, 70 glState.getRasterizerState().frontFace, true); 71 72 mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); 73 74 mRenderer->clear(clearParams, mRenderTargetCache.getColors()[0], 75 mRenderTargetCache.getDepthStencil()); 76 return angle::Result::Continue; 77 } 78 79 angle::Result Framebuffer9::readPixelsImpl(const gl::Context *context, 80 const gl::Rectangle &area, 81 GLenum format, 82 GLenum type, 83 size_t outputPitch, 84 const gl::PixelPackState &pack, 85 gl::Buffer *packBuffer, 86 uint8_t *pixels) 87 { 88 const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0); 89 ASSERT(colorbuffer); 90 91 RenderTarget9 *renderTarget = nullptr; 92 ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget)); 93 ASSERT(renderTarget); 94 95 IDirect3DSurface9 *surface = renderTarget->getSurface(); 96 ASSERT(surface); 97 98 D3DSURFACE_DESC desc; 99 surface->GetDesc(&desc); 100 101 Context9 *context9 = GetImplAs<Context9>(context); 102 103 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) 104 { 105 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render 106 // target 107 SafeRelease(surface); 108 ANGLE_TRY_HR(context9, E_OUTOFMEMORY, 109 "ReadPixels is unimplemented for multisampled framebuffer attachments."); 110 } 111 112 IDirect3DDevice9 *device = mRenderer->getDevice(); 113 ASSERT(device); 114 115 HRESULT result; 116 IDirect3DSurface9 *systemSurface = nullptr; 117 bool directToPixels = 118 !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() && 119 area.x == 0 && area.y == 0 && static_cast<UINT>(area.width) == desc.Width && 120 static_cast<UINT>(area.height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 && 121 format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; 122 if (directToPixels) 123 { 124 // Use the pixels ptr as a shared handle to write directly into client's memory 125 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, 126 D3DPOOL_SYSTEMMEM, &systemSurface, 127 reinterpret_cast<void **>(&pixels)); 128 if (FAILED(result)) 129 { 130 // Try again without the shared handle 131 directToPixels = false; 132 } 133 } 134 135 if (!directToPixels) 136 { 137 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, 138 D3DPOOL_SYSTEMMEM, &systemSurface, nullptr); 139 if (FAILED(result)) 140 { 141 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 142 SafeRelease(surface); 143 ANGLE_TRY_HR(context9, E_OUTOFMEMORY, 144 "Failed to allocate internal texture for ReadPixels."); 145 } 146 } 147 148 result = device->GetRenderTargetData(surface, systemSurface); 149 SafeRelease(surface); 150 151 if (FAILED(result)) 152 { 153 SafeRelease(systemSurface); 154 155 // It turns out that D3D will sometimes produce more error 156 // codes than those documented. 157 if (d3d9::isDeviceLostError(result)) 158 { 159 mRenderer->notifyDeviceLost(); 160 } 161 else 162 { 163 UNREACHABLE(); 164 } 165 166 ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to read internal render target data."); 167 } 168 169 if (directToPixels) 170 { 171 SafeRelease(systemSurface); 172 return angle::Result::Continue; 173 } 174 175 RECT rect; 176 rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width)); 177 rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height)); 178 rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width)); 179 rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height)); 180 181 D3DLOCKED_RECT lock; 182 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); 183 184 if (FAILED(result)) 185 { 186 UNREACHABLE(); 187 SafeRelease(systemSurface); 188 189 ANGLE_TRY_HR(context9, E_OUTOFMEMORY, "Failed to lock internal render target."); 190 } 191 192 uint8_t *source = static_cast<uint8_t *>(lock.pBits); 193 int inputPitch = lock.Pitch; 194 195 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); 196 197 gl::FormatType formatType(format, type); 198 199 PackPixelsParams packParams; 200 packParams.area.x = rect.left; 201 packParams.area.y = rect.top; 202 packParams.area.width = rect.right - rect.left; 203 packParams.area.height = rect.bottom - rect.top; 204 packParams.destFormat = &GetFormatFromFormatType(format, type); 205 packParams.outputPitch = static_cast<GLuint>(outputPitch); 206 packParams.reverseRowOrder = pack.reverseRowOrder; 207 208 PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels); 209 210 systemSurface->UnlockRect(); 211 SafeRelease(systemSurface); 212 213 return angle::Result::Continue; 214 } 215 216 angle::Result Framebuffer9::blitImpl(const gl::Context *context, 217 const gl::Rectangle &sourceArea, 218 const gl::Rectangle &destArea, 219 const gl::Rectangle *scissor, 220 bool blitRenderTarget, 221 bool blitDepth, 222 bool blitStencil, 223 GLenum filter, 224 const gl::Framebuffer *sourceFramebuffer) 225 { 226 ASSERT(filter == GL_NEAREST); 227 228 IDirect3DDevice9 *device = mRenderer->getDevice(); 229 ASSERT(device); 230 231 mRenderer->endScene(); 232 233 Context9 *context9 = GetImplAs<Context9>(context); 234 235 if (blitRenderTarget) 236 { 237 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorAttachment(0); 238 ASSERT(readBuffer); 239 240 RenderTarget9 *readRenderTarget = nullptr; 241 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget)); 242 ASSERT(readRenderTarget); 243 244 const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0); 245 ASSERT(drawBuffer); 246 247 RenderTarget9 *drawRenderTarget = nullptr; 248 ANGLE_TRY( 249 drawBuffer->getRenderTarget(context, drawBuffer->getSamples(), &drawRenderTarget)); 250 ASSERT(drawRenderTarget); 251 252 // The getSurface calls do an AddRef so save them until after no errors are possible 253 IDirect3DSurface9 *readSurface = readRenderTarget->getSurface(); 254 ASSERT(readSurface); 255 256 IDirect3DSurface9 *drawSurface = drawRenderTarget->getSurface(); 257 ASSERT(drawSurface); 258 259 gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); 260 gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); 261 262 RECT srcRect; 263 srcRect.left = sourceArea.x; 264 srcRect.right = sourceArea.x + sourceArea.width; 265 srcRect.top = sourceArea.y; 266 srcRect.bottom = sourceArea.y + sourceArea.height; 267 268 RECT dstRect; 269 dstRect.left = destArea.x; 270 dstRect.right = destArea.x + destArea.width; 271 dstRect.top = destArea.y; 272 dstRect.bottom = destArea.y + destArea.height; 273 274 // Clip the rectangles to the scissor rectangle 275 if (scissor) 276 { 277 if (dstRect.left < scissor->x) 278 { 279 srcRect.left += (scissor->x - dstRect.left); 280 dstRect.left = scissor->x; 281 } 282 if (dstRect.top < scissor->y) 283 { 284 srcRect.top += (scissor->y - dstRect.top); 285 dstRect.top = scissor->y; 286 } 287 if (dstRect.right > scissor->x + scissor->width) 288 { 289 srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); 290 dstRect.right = scissor->x + scissor->width; 291 } 292 if (dstRect.bottom > scissor->y + scissor->height) 293 { 294 srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); 295 dstRect.bottom = scissor->y + scissor->height; 296 } 297 } 298 299 // Clip the rectangles to the destination size 300 if (dstRect.left < 0) 301 { 302 srcRect.left += -dstRect.left; 303 dstRect.left = 0; 304 } 305 if (dstRect.right > dstSize.width) 306 { 307 srcRect.right -= (dstRect.right - dstSize.width); 308 dstRect.right = dstSize.width; 309 } 310 if (dstRect.top < 0) 311 { 312 srcRect.top += -dstRect.top; 313 dstRect.top = 0; 314 } 315 if (dstRect.bottom > dstSize.height) 316 { 317 srcRect.bottom -= (dstRect.bottom - dstSize.height); 318 dstRect.bottom = dstSize.height; 319 } 320 321 // Clip the rectangles to the source size 322 if (srcRect.left < 0) 323 { 324 dstRect.left += -srcRect.left; 325 srcRect.left = 0; 326 } 327 if (srcRect.right > srcSize.width) 328 { 329 dstRect.right -= (srcRect.right - srcSize.width); 330 srcRect.right = srcSize.width; 331 } 332 if (srcRect.top < 0) 333 { 334 dstRect.top += -srcRect.top; 335 srcRect.top = 0; 336 } 337 if (srcRect.bottom > srcSize.height) 338 { 339 dstRect.bottom -= (srcRect.bottom - srcSize.height); 340 srcRect.bottom = srcSize.height; 341 } 342 343 HRESULT result = 344 device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); 345 346 SafeRelease(readSurface); 347 SafeRelease(drawSurface); 348 349 ANGLE_TRY_HR(context9, result, "Internal blit failed."); 350 } 351 352 if (blitDepth || blitStencil) 353 { 354 const gl::FramebufferAttachment *readBuffer = 355 sourceFramebuffer->getDepthOrStencilAttachment(); 356 ASSERT(readBuffer); 357 358 RenderTarget9 *readDepthStencil = nullptr; 359 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readDepthStencil)); 360 ASSERT(readDepthStencil); 361 362 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); 363 ASSERT(drawBuffer); 364 365 RenderTarget9 *drawDepthStencil = nullptr; 366 ANGLE_TRY( 367 drawBuffer->getRenderTarget(context, drawBuffer->getSamples(), &drawDepthStencil)); 368 ASSERT(drawDepthStencil); 369 370 // The getSurface calls do an AddRef so save them until after no errors are possible 371 IDirect3DSurface9 *readSurface = readDepthStencil->getSurface(); 372 ASSERT(readDepthStencil); 373 374 IDirect3DSurface9 *drawSurface = drawDepthStencil->getSurface(); 375 ASSERT(drawDepthStencil); 376 377 HRESULT result = 378 device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE); 379 380 SafeRelease(readSurface); 381 SafeRelease(drawSurface); 382 383 ANGLE_TRY_HR(context9, result, "Internal blit failed."); 384 } 385 386 return angle::Result::Continue; 387 } 388 389 const gl::InternalFormat &Framebuffer9::getImplementationColorReadFormat( 390 const gl::Context *context) const 391 { 392 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat; 393 const d3d9::TextureFormat &textureFormat = d3d9::GetTextureFormatInfo(sizedFormat); 394 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(textureFormat.renderFormat); 395 const angle::Format &angleFormat = angle::Format::Get(d3dFormatInfo.formatID); 396 return gl::GetSizedInternalFormatInfo(angleFormat.fboImplementationInternalFormat); 397 } 398 399 angle::Result Framebuffer9::getSamplePosition(const gl::Context *context, 400 size_t index, 401 GLfloat *xy) const 402 { 403 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 404 return angle::Result::Stop; 405 } 406 407 angle::Result Framebuffer9::syncState(const gl::Context *context, 408 GLenum binding, 409 const gl::Framebuffer::DirtyBits &dirtyBits, 410 gl::Command command) 411 { 412 ANGLE_TRY(FramebufferD3D::syncState(context, binding, dirtyBits, command)); 413 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits)); 414 return angle::Result::Continue; 415 } 416 } // namespace rx