1 #include "precompiled.h" 2 // 3 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 8 // Image9.cpp: Implements the rx::Image9 class, which acts as the interface to 9 // the actual underlying surfaces of a Texture. 10 11 #include "libGLESv2/renderer/d3d9/Image9.h" 12 13 #include "libGLESv2/main.h" 14 #include "libGLESv2/Framebuffer.h" 15 #include "libGLESv2/Renderbuffer.h" 16 #include "libGLESv2/renderer/d3d9/Renderer9.h" 17 #include "libGLESv2/renderer/d3d9/RenderTarget9.h" 18 #include "libGLESv2/renderer/d3d9/TextureStorage9.h" 19 20 #include "libGLESv2/renderer/d3d9/renderer9_utils.h" 21 #include "libGLESv2/renderer/d3d9/formatutils9.h" 22 23 namespace rx 24 { 25 26 Image9::Image9() 27 { 28 mSurface = NULL; 29 mRenderer = NULL; 30 31 mD3DPool = D3DPOOL_SYSTEMMEM; 32 mD3DFormat = D3DFMT_UNKNOWN; 33 } 34 35 Image9::~Image9() 36 { 37 SafeRelease(mSurface); 38 } 39 40 void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) 41 { 42 D3DSURFACE_DESC destDesc; 43 HRESULT result = destSurface->GetDesc(&destDesc); 44 ASSERT(SUCCEEDED(result)); 45 46 D3DSURFACE_DESC sourceDesc; 47 result = sourceSurface->GetDesc(&sourceDesc); 48 ASSERT(SUCCEEDED(result)); 49 50 ASSERT(sourceDesc.Format == destDesc.Format); 51 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); 52 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); 53 54 MipGenerationFunction mipFunction = d3d9::GetMipGenerationFunction(sourceDesc.Format); 55 ASSERT(mipFunction != NULL); 56 57 D3DLOCKED_RECT sourceLocked = {0}; 58 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); 59 ASSERT(SUCCEEDED(result)); 60 61 D3DLOCKED_RECT destLocked = {0}; 62 result = destSurface->LockRect(&destLocked, NULL, 0); 63 ASSERT(SUCCEEDED(result)); 64 65 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits); 66 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits); 67 68 if (sourceData && destData) 69 { 70 mipFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, 71 destData, destLocked.Pitch, 0); 72 } 73 74 destSurface->UnlockRect(); 75 sourceSurface->UnlockRect(); 76 } 77 78 Image9 *Image9::makeImage9(Image *img) 79 { 80 ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img)); 81 return static_cast<rx::Image9*>(img); 82 } 83 84 void Image9::generateMipmap(Image9 *dest, Image9 *source) 85 { 86 IDirect3DSurface9 *sourceSurface = source->getSurface(); 87 if (sourceSurface == NULL) 88 return gl::error(GL_OUT_OF_MEMORY); 89 90 IDirect3DSurface9 *destSurface = dest->getSurface(); 91 generateMip(destSurface, sourceSurface); 92 93 dest->markDirty(); 94 } 95 96 void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) 97 { 98 D3DLOCKED_RECT sourceLock = {0}; 99 D3DLOCKED_RECT destLock = {0}; 100 101 source->LockRect(&sourceLock, NULL, 0); 102 dest->LockRect(&destLock, NULL, 0); 103 104 if (sourceLock.pBits && destLock.pBits) 105 { 106 D3DSURFACE_DESC desc; 107 source->GetDesc(&desc); 108 109 int blockHeight = d3d9::GetBlockHeight(desc.Format); 110 int rows = desc.Height / blockHeight; 111 112 int bytes = d3d9::GetBlockSize(desc.Format, desc.Width, blockHeight); 113 ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch); 114 115 for(int i = 0; i < rows; i++) 116 { 117 memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); 118 } 119 120 source->UnlockRect(); 121 dest->UnlockRect(); 122 } 123 else UNREACHABLE(); 124 } 125 126 bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) 127 { 128 // 3D textures are not supported by the D3D9 backend. 129 ASSERT(depth <= 1); 130 131 // Only 2D and cube texture are supported by the D3D9 backend. 132 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); 133 134 if (mWidth != width || 135 mHeight != height || 136 mDepth != depth || 137 mInternalFormat != internalformat || 138 forceRelease) 139 { 140 mRenderer = Renderer9::makeRenderer9(renderer); 141 142 mWidth = width; 143 mHeight = height; 144 mDepth = depth; 145 mInternalFormat = internalformat; 146 147 // compute the d3d format that will be used 148 mD3DFormat = gl_d3d9::GetTextureFormat(internalformat, mRenderer); 149 mActualFormat = d3d9_gl::GetInternalFormat(mD3DFormat); 150 mRenderable = gl_d3d9::GetRenderFormat(internalformat, mRenderer) != D3DFMT_UNKNOWN; 151 152 SafeRelease(mSurface); 153 mDirty = gl_d3d9::RequiresTextureDataInitialization(mInternalFormat); 154 155 return true; 156 } 157 158 return false; 159 } 160 161 void Image9::createSurface() 162 { 163 if(mSurface) 164 { 165 return; 166 } 167 168 IDirect3DTexture9 *newTexture = NULL; 169 IDirect3DSurface9 *newSurface = NULL; 170 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; 171 const D3DFORMAT d3dFormat = getD3DFormat(); 172 173 if (mWidth != 0 && mHeight != 0) 174 { 175 int levelToFetch = 0; 176 GLsizei requestWidth = mWidth; 177 GLsizei requestHeight = mHeight; 178 d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch); 179 180 IDirect3DDevice9 *device = mRenderer->getDevice(); 181 182 HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, 183 poolToUse, &newTexture, NULL); 184 185 if (FAILED(result)) 186 { 187 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 188 ERR("Creating image surface failed."); 189 return gl::error(GL_OUT_OF_MEMORY); 190 } 191 192 newTexture->GetSurfaceLevel(levelToFetch, &newSurface); 193 SafeRelease(newTexture); 194 195 if (gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) 196 { 197 InitializeTextureDataFunction initializeFunc = gl_d3d9::GetTextureDataInitializationFunction(mInternalFormat); 198 199 RECT entireRect; 200 entireRect.left = 0; 201 entireRect.right = mWidth; 202 entireRect.top = 0; 203 entireRect.bottom = mHeight; 204 205 D3DLOCKED_RECT lockedRect; 206 result = newSurface->LockRect(&lockedRect, &entireRect, 0); 207 ASSERT(SUCCEEDED(result)); 208 209 initializeFunc(mWidth, mHeight, 1, lockedRect.pBits, lockedRect.Pitch, 0); 210 211 result = newSurface->UnlockRect(); 212 ASSERT(SUCCEEDED(result)); 213 } 214 } 215 216 mSurface = newSurface; 217 mDirty = false; 218 mD3DPool = poolToUse; 219 } 220 221 HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) 222 { 223 createSurface(); 224 225 HRESULT result = D3DERR_INVALIDCALL; 226 227 if (mSurface) 228 { 229 result = mSurface->LockRect(lockedRect, rect, 0); 230 ASSERT(SUCCEEDED(result)); 231 232 mDirty = true; 233 } 234 235 return result; 236 } 237 238 void Image9::unlock() 239 { 240 if (mSurface) 241 { 242 HRESULT result = mSurface->UnlockRect(); 243 UNUSED_ASSERTION_VARIABLE(result); 244 ASSERT(SUCCEEDED(result)); 245 } 246 } 247 248 D3DFORMAT Image9::getD3DFormat() const 249 { 250 // this should only happen if the image hasn't been redefined first 251 // which would be a bug by the caller 252 ASSERT(mD3DFormat != D3DFMT_UNKNOWN); 253 254 return mD3DFormat; 255 } 256 257 bool Image9::isDirty() const 258 { 259 // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet 260 // if initialization is required before use. 261 return (mSurface || gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) && mDirty; 262 } 263 264 IDirect3DSurface9 *Image9::getSurface() 265 { 266 createSurface(); 267 268 return mSurface; 269 } 270 271 void Image9::setManagedSurface(TextureStorageInterface2D *storage, int level) 272 { 273 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); 274 setManagedSurface(storage9->getSurfaceLevel(level, false)); 275 } 276 277 void Image9::setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level) 278 { 279 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); 280 setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false)); 281 } 282 283 void Image9::setManagedSurface(IDirect3DSurface9 *surface) 284 { 285 D3DSURFACE_DESC desc; 286 surface->GetDesc(&desc); 287 ASSERT(desc.Pool == D3DPOOL_MANAGED); 288 289 if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight) 290 { 291 if (mSurface) 292 { 293 copyLockableSurfaces(surface, mSurface); 294 SafeRelease(mSurface); 295 } 296 297 mSurface = surface; 298 mD3DPool = desc.Pool; 299 } 300 } 301 302 bool Image9::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 303 { 304 ASSERT(getSurface() != NULL); 305 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); 306 return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); 307 } 308 309 bool Image9::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 310 { 311 ASSERT(getSurface() != NULL); 312 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); 313 return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); 314 } 315 316 bool Image9::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) 317 { 318 // 3D textures are not supported by the D3D9 backend. 319 UNREACHABLE(); 320 return false; 321 } 322 323 bool Image9::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) 324 { 325 // 2D array textures are not supported by the D3D9 backend. 326 UNREACHABLE(); 327 return false; 328 } 329 330 bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 331 { 332 ASSERT(width > 0 && height > 0); 333 334 if (!destSurface) 335 return false; 336 337 IDirect3DSurface9 *sourceSurface = getSurface(); 338 339 if (sourceSurface && sourceSurface != destSurface) 340 { 341 RECT rect; 342 rect.left = xoffset; 343 rect.top = yoffset; 344 rect.right = xoffset + width; 345 rect.bottom = yoffset + height; 346 347 POINT point = {rect.left, rect.top}; 348 349 IDirect3DDevice9 *device = mRenderer->getDevice(); 350 351 if (mD3DPool == D3DPOOL_MANAGED) 352 { 353 D3DSURFACE_DESC desc; 354 sourceSurface->GetDesc(&desc); 355 356 IDirect3DSurface9 *surf = 0; 357 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); 358 359 if (SUCCEEDED(result)) 360 { 361 copyLockableSurfaces(surf, sourceSurface); 362 result = device->UpdateSurface(surf, &rect, destSurface, &point); 363 ASSERT(SUCCEEDED(result)); 364 SafeRelease(surf); 365 } 366 } 367 else 368 { 369 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools 370 HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); 371 UNUSED_ASSERTION_VARIABLE(result); 372 ASSERT(SUCCEEDED(result)); 373 } 374 } 375 376 SafeRelease(destSurface); 377 return true; 378 } 379 380 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input 381 // into the target pixel rectangle. 382 void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 383 GLint unpackAlignment, GLenum type, const void *input) 384 { 385 // 3D textures are not supported by the D3D9 backend. 386 ASSERT(zoffset == 0 && depth == 1); 387 388 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 389 GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, clientVersion, width, unpackAlignment); 390 391 LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat, mRenderer); 392 ASSERT(loadFunction != NULL); 393 394 RECT lockRect = 395 { 396 xoffset, yoffset, 397 xoffset + width, yoffset + height 398 }; 399 400 D3DLOCKED_RECT locked; 401 HRESULT result = lock(&locked, &lockRect); 402 if (FAILED(result)) 403 { 404 return; 405 } 406 407 loadFunction(width, height, depth, input, inputRowPitch, 0, locked.pBits, locked.Pitch, 0); 408 409 unlock(); 410 } 411 412 void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 413 const void *input) 414 { 415 // 3D textures are not supported by the D3D9 backend. 416 ASSERT(zoffset == 0 && depth == 1); 417 418 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 419 GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, 1); 420 GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, height, 1); 421 422 ASSERT(xoffset % d3d9::GetBlockWidth(mD3DFormat) == 0); 423 ASSERT(yoffset % d3d9::GetBlockHeight(mD3DFormat) == 0); 424 425 LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat, mRenderer); 426 ASSERT(loadFunction != NULL); 427 428 RECT lockRect = 429 { 430 xoffset, yoffset, 431 xoffset + width, yoffset + height 432 }; 433 434 D3DLOCKED_RECT locked; 435 HRESULT result = lock(&locked, &lockRect); 436 if (FAILED(result)) 437 { 438 return; 439 } 440 441 loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch, 442 locked.pBits, locked.Pitch, 0); 443 444 unlock(); 445 } 446 447 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures 448 void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 449 { 450 // ES3.0 only behaviour to copy into a 3d texture 451 ASSERT(zoffset == 0); 452 453 RenderTarget9 *renderTarget = NULL; 454 IDirect3DSurface9 *surface = NULL; 455 gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0); 456 457 if (colorbuffer) 458 { 459 renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); 460 } 461 462 if (renderTarget) 463 { 464 surface = renderTarget->getSurface(); 465 } 466 467 if (!surface) 468 { 469 ERR("Failed to retrieve the render target."); 470 return gl::error(GL_OUT_OF_MEMORY); 471 } 472 473 IDirect3DDevice9 *device = mRenderer->getDevice(); 474 475 IDirect3DSurface9 *renderTargetData = NULL; 476 D3DSURFACE_DESC description; 477 surface->GetDesc(&description); 478 479 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); 480 481 if (FAILED(result)) 482 { 483 ERR("Could not create matching destination surface."); 484 SafeRelease(surface); 485 return gl::error(GL_OUT_OF_MEMORY); 486 } 487 488 result = device->GetRenderTargetData(surface, renderTargetData); 489 490 if (FAILED(result)) 491 { 492 ERR("GetRenderTargetData unexpectedly failed."); 493 SafeRelease(renderTargetData); 494 SafeRelease(surface); 495 return gl::error(GL_OUT_OF_MEMORY); 496 } 497 498 RECT sourceRect = {x, y, x + width, y + height}; 499 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; 500 501 D3DLOCKED_RECT sourceLock = {0}; 502 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); 503 504 if (FAILED(result)) 505 { 506 ERR("Failed to lock the source surface (rectangle might be invalid)."); 507 SafeRelease(renderTargetData); 508 SafeRelease(surface); 509 return gl::error(GL_OUT_OF_MEMORY); 510 } 511 512 D3DLOCKED_RECT destLock = {0}; 513 result = lock(&destLock, &destRect); 514 515 if (FAILED(result)) 516 { 517 ERR("Failed to lock the destination surface (rectangle might be invalid)."); 518 renderTargetData->UnlockRect(); 519 SafeRelease(renderTargetData); 520 SafeRelease(surface); 521 return gl::error(GL_OUT_OF_MEMORY); 522 } 523 524 if (destLock.pBits && sourceLock.pBits) 525 { 526 unsigned char *source = (unsigned char*)sourceLock.pBits; 527 unsigned char *dest = (unsigned char*)destLock.pBits; 528 529 switch (description.Format) 530 { 531 case D3DFMT_X8R8G8B8: 532 case D3DFMT_A8R8G8B8: 533 switch(getD3DFormat()) 534 { 535 case D3DFMT_X8R8G8B8: 536 case D3DFMT_A8R8G8B8: 537 for(int y = 0; y < height; y++) 538 { 539 memcpy(dest, source, 4 * width); 540 541 source += sourceLock.Pitch; 542 dest += destLock.Pitch; 543 } 544 break; 545 case D3DFMT_L8: 546 for(int y = 0; y < height; y++) 547 { 548 for(int x = 0; x < width; x++) 549 { 550 dest[x] = source[x * 4 + 2]; 551 } 552 553 source += sourceLock.Pitch; 554 dest += destLock.Pitch; 555 } 556 break; 557 case D3DFMT_A8L8: 558 for(int y = 0; y < height; y++) 559 { 560 for(int x = 0; x < width; x++) 561 { 562 dest[x * 2 + 0] = source[x * 4 + 2]; 563 dest[x * 2 + 1] = source[x * 4 + 3]; 564 } 565 566 source += sourceLock.Pitch; 567 dest += destLock.Pitch; 568 } 569 break; 570 default: 571 UNREACHABLE(); 572 } 573 break; 574 case D3DFMT_R5G6B5: 575 switch(getD3DFormat()) 576 { 577 case D3DFMT_X8R8G8B8: 578 for(int y = 0; y < height; y++) 579 { 580 for(int x = 0; x < width; x++) 581 { 582 unsigned short rgb = ((unsigned short*)source)[x]; 583 unsigned char red = (rgb & 0xF800) >> 8; 584 unsigned char green = (rgb & 0x07E0) >> 3; 585 unsigned char blue = (rgb & 0x001F) << 3; 586 dest[x + 0] = blue | (blue >> 5); 587 dest[x + 1] = green | (green >> 6); 588 dest[x + 2] = red | (red >> 5); 589 dest[x + 3] = 0xFF; 590 } 591 592 source += sourceLock.Pitch; 593 dest += destLock.Pitch; 594 } 595 break; 596 case D3DFMT_L8: 597 for(int y = 0; y < height; y++) 598 { 599 for(int x = 0; x < width; x++) 600 { 601 unsigned char red = source[x * 2 + 1] & 0xF8; 602 dest[x] = red | (red >> 5); 603 } 604 605 source += sourceLock.Pitch; 606 dest += destLock.Pitch; 607 } 608 break; 609 default: 610 UNREACHABLE(); 611 } 612 break; 613 case D3DFMT_A1R5G5B5: 614 switch(getD3DFormat()) 615 { 616 case D3DFMT_X8R8G8B8: 617 for(int y = 0; y < height; y++) 618 { 619 for(int x = 0; x < width; x++) 620 { 621 unsigned short argb = ((unsigned short*)source)[x]; 622 unsigned char red = (argb & 0x7C00) >> 7; 623 unsigned char green = (argb & 0x03E0) >> 2; 624 unsigned char blue = (argb & 0x001F) << 3; 625 dest[x + 0] = blue | (blue >> 5); 626 dest[x + 1] = green | (green >> 5); 627 dest[x + 2] = red | (red >> 5); 628 dest[x + 3] = 0xFF; 629 } 630 631 source += sourceLock.Pitch; 632 dest += destLock.Pitch; 633 } 634 break; 635 case D3DFMT_A8R8G8B8: 636 for(int y = 0; y < height; y++) 637 { 638 for(int x = 0; x < width; x++) 639 { 640 unsigned short argb = ((unsigned short*)source)[x]; 641 unsigned char red = (argb & 0x7C00) >> 7; 642 unsigned char green = (argb & 0x03E0) >> 2; 643 unsigned char blue = (argb & 0x001F) << 3; 644 unsigned char alpha = (signed short)argb >> 15; 645 dest[x + 0] = blue | (blue >> 5); 646 dest[x + 1] = green | (green >> 5); 647 dest[x + 2] = red | (red >> 5); 648 dest[x + 3] = alpha; 649 } 650 651 source += sourceLock.Pitch; 652 dest += destLock.Pitch; 653 } 654 break; 655 case D3DFMT_L8: 656 for(int y = 0; y < height; y++) 657 { 658 for(int x = 0; x < width; x++) 659 { 660 unsigned char red = source[x * 2 + 1] & 0x7C; 661 dest[x] = (red << 1) | (red >> 4); 662 } 663 664 source += sourceLock.Pitch; 665 dest += destLock.Pitch; 666 } 667 break; 668 case D3DFMT_A8L8: 669 for(int y = 0; y < height; y++) 670 { 671 for(int x = 0; x < width; x++) 672 { 673 unsigned char red = source[x * 2 + 1] & 0x7C; 674 dest[x * 2 + 0] = (red << 1) | (red >> 4); 675 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; 676 } 677 678 source += sourceLock.Pitch; 679 dest += destLock.Pitch; 680 } 681 break; 682 default: 683 UNREACHABLE(); 684 } 685 break; 686 default: 687 UNREACHABLE(); 688 } 689 } 690 691 unlock(); 692 renderTargetData->UnlockRect(); 693 694 SafeRelease(renderTargetData); 695 SafeRelease(surface); 696 697 mDirty = true; 698 } 699 700 } 701