Home | History | Annotate | Download | only in renderer
      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/Image9.h"
     12 
     13 #include "libGLESv2/main.h"
     14 #include "libGLESv2/Framebuffer.h"
     15 #include "libGLESv2/Renderbuffer.h"
     16 #include "libGLESv2/renderer/Renderer9.h"
     17 #include "libGLESv2/renderer/RenderTarget9.h"
     18 #include "libGLESv2/renderer/TextureStorage9.h"
     19 
     20 #include "libGLESv2/renderer/renderer9_utils.h"
     21 #include "libGLESv2/renderer/generatemip.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     if (mSurface)
     38     {
     39         mSurface->Release();
     40     }
     41 }
     42 
     43 void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
     44 {
     45     D3DSURFACE_DESC destDesc;
     46     HRESULT result = destSurface->GetDesc(&destDesc);
     47     ASSERT(SUCCEEDED(result));
     48 
     49     D3DSURFACE_DESC sourceDesc;
     50     result = sourceSurface->GetDesc(&sourceDesc);
     51     ASSERT(SUCCEEDED(result));
     52 
     53     ASSERT(sourceDesc.Format == destDesc.Format);
     54     ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
     55     ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
     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         switch (sourceDesc.Format)
     71         {
     72           case D3DFMT_L8:
     73             GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
     74             break;
     75           case D3DFMT_A8L8:
     76             GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
     77             break;
     78           case D3DFMT_A8R8G8B8:
     79           case D3DFMT_X8R8G8B8:
     80             GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
     81             break;
     82           case D3DFMT_A16B16G16R16F:
     83             GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
     84             break;
     85           case D3DFMT_A32B32G32R32F:
     86             GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
     87             break;
     88           default:
     89             UNREACHABLE();
     90             break;
     91         }
     92 
     93         destSurface->UnlockRect();
     94         sourceSurface->UnlockRect();
     95     }
     96 }
     97 
     98 Image9 *Image9::makeImage9(Image *img)
     99 {
    100     ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img));
    101     return static_cast<rx::Image9*>(img);
    102 }
    103 
    104 void Image9::generateMipmap(Image9 *dest, Image9 *source)
    105 {
    106     IDirect3DSurface9 *sourceSurface = source->getSurface();
    107     if (sourceSurface == NULL)
    108         return gl::error(GL_OUT_OF_MEMORY);
    109 
    110     IDirect3DSurface9 *destSurface = dest->getSurface();
    111     generateMip(destSurface, sourceSurface);
    112 
    113     dest->markDirty();
    114 }
    115 
    116 void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
    117 {
    118     D3DLOCKED_RECT sourceLock = {0};
    119     D3DLOCKED_RECT destLock = {0};
    120 
    121     source->LockRect(&sourceLock, NULL, 0);
    122     dest->LockRect(&destLock, NULL, 0);
    123 
    124     if (sourceLock.pBits && destLock.pBits)
    125     {
    126         D3DSURFACE_DESC desc;
    127         source->GetDesc(&desc);
    128 
    129         int rows = d3d9::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height;
    130         int bytes = d3d9::ComputeRowSize(desc.Format, desc.Width);
    131         ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch);
    132 
    133         for(int i = 0; i < rows; i++)
    134         {
    135             memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
    136         }
    137 
    138         source->UnlockRect();
    139         dest->UnlockRect();
    140     }
    141     else UNREACHABLE();
    142 }
    143 
    144 bool Image9::redefine(rx::Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
    145 {
    146     if (mWidth != width ||
    147         mHeight != height ||
    148         mInternalFormat != internalformat ||
    149         forceRelease)
    150     {
    151         mRenderer = Renderer9::makeRenderer9(renderer);
    152 
    153         mWidth = width;
    154         mHeight = height;
    155         mInternalFormat = internalformat;
    156         // compute the d3d format that will be used
    157         mD3DFormat = mRenderer->ConvertTextureInternalFormat(internalformat);
    158         mActualFormat = d3d9_gl::GetEquivalentFormat(mD3DFormat);
    159 
    160         if (mSurface)
    161         {
    162             mSurface->Release();
    163             mSurface = NULL;
    164         }
    165 
    166         return true;
    167     }
    168 
    169     return false;
    170 }
    171 
    172 void Image9::createSurface()
    173 {
    174     if(mSurface)
    175     {
    176         return;
    177     }
    178 
    179     IDirect3DTexture9 *newTexture = NULL;
    180     IDirect3DSurface9 *newSurface = NULL;
    181     const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
    182     const D3DFORMAT d3dFormat = getD3DFormat();
    183     ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
    184 
    185     if (mWidth != 0 && mHeight != 0)
    186     {
    187         int levelToFetch = 0;
    188         GLsizei requestWidth = mWidth;
    189         GLsizei requestHeight = mHeight;
    190         gl::MakeValidSize(true, gl::IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch);
    191 
    192         IDirect3DDevice9 *device = mRenderer->getDevice();
    193 
    194         HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat,
    195                                                     poolToUse, &newTexture, NULL);
    196 
    197         if (FAILED(result))
    198         {
    199             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
    200             ERR("Creating image surface failed.");
    201             return gl::error(GL_OUT_OF_MEMORY);
    202         }
    203 
    204         newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
    205         newTexture->Release();
    206     }
    207 
    208     mSurface = newSurface;
    209     mDirty = false;
    210     mD3DPool = poolToUse;
    211 }
    212 
    213 HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
    214 {
    215     createSurface();
    216 
    217     HRESULT result = D3DERR_INVALIDCALL;
    218 
    219     if (mSurface)
    220     {
    221         result = mSurface->LockRect(lockedRect, rect, 0);
    222         ASSERT(SUCCEEDED(result));
    223 
    224         mDirty = true;
    225     }
    226 
    227     return result;
    228 }
    229 
    230 void Image9::unlock()
    231 {
    232     if (mSurface)
    233     {
    234         HRESULT result = mSurface->UnlockRect();
    235         ASSERT(SUCCEEDED(result));
    236     }
    237 }
    238 
    239 bool Image9::isRenderableFormat() const
    240 {
    241     return TextureStorage9::IsTextureFormatRenderable(getD3DFormat());
    242 }
    243 
    244 D3DFORMAT Image9::getD3DFormat() const
    245 {
    246     // this should only happen if the image hasn't been redefined first
    247     // which would be a bug by the caller
    248     ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
    249 
    250     return mD3DFormat;
    251 }
    252 
    253 IDirect3DSurface9 *Image9::getSurface()
    254 {
    255     createSurface();
    256 
    257     return mSurface;
    258 }
    259 
    260 void Image9::setManagedSurface(TextureStorageInterface2D *storage, int level)
    261 {
    262     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
    263     setManagedSurface(storage9->getSurfaceLevel(level, false));
    264 }
    265 
    266 void Image9::setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level)
    267 {
    268     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
    269     setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
    270 }
    271 
    272 void Image9::setManagedSurface(IDirect3DSurface9 *surface)
    273 {
    274     D3DSURFACE_DESC desc;
    275     surface->GetDesc(&desc);
    276     ASSERT(desc.Pool == D3DPOOL_MANAGED);
    277 
    278     if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
    279     {
    280         if (mSurface)
    281         {
    282             copyLockableSurfaces(surface, mSurface);
    283             mSurface->Release();
    284         }
    285 
    286         mSurface = surface;
    287         mD3DPool = desc.Pool;
    288     }
    289 }
    290 
    291 bool Image9::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    292 {
    293     ASSERT(getSurface() != NULL);
    294     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
    295     return updateSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
    296 }
    297 
    298 bool Image9::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    299 {
    300     ASSERT(getSurface() != NULL);
    301     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
    302     return updateSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
    303 }
    304 
    305 bool Image9::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    306 {
    307     if (!destSurface)
    308         return false;
    309 
    310     IDirect3DSurface9 *sourceSurface = getSurface();
    311 
    312     if (sourceSurface && sourceSurface != destSurface)
    313     {
    314         RECT rect;
    315         rect.left = xoffset;
    316         rect.top = yoffset;
    317         rect.right = xoffset + width;
    318         rect.bottom = yoffset + height;
    319 
    320         POINT point = {rect.left, rect.top};
    321 
    322         IDirect3DDevice9 *device = mRenderer->getDevice();
    323 
    324         if (mD3DPool == D3DPOOL_MANAGED)
    325         {
    326             D3DSURFACE_DESC desc;
    327             sourceSurface->GetDesc(&desc);
    328 
    329             IDirect3DSurface9 *surf = 0;
    330             HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
    331 
    332             if (SUCCEEDED(result))
    333             {
    334                 copyLockableSurfaces(surf, sourceSurface);
    335                 result = device->UpdateSurface(surf, &rect, destSurface, &point);
    336                 ASSERT(SUCCEEDED(result));
    337                 surf->Release();
    338             }
    339         }
    340         else
    341         {
    342             // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
    343             HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
    344             ASSERT(SUCCEEDED(result));
    345         }
    346     }
    347 
    348     destSurface->Release();
    349     return true;
    350 }
    351 
    352 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
    353 // into the target pixel rectangle.
    354 void Image9::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
    355                       GLint unpackAlignment, const void *input)
    356 {
    357     RECT lockRect =
    358     {
    359         xoffset, yoffset,
    360         xoffset + width, yoffset + height
    361     };
    362 
    363     D3DLOCKED_RECT locked;
    364     HRESULT result = lock(&locked, &lockRect);
    365     if (FAILED(result))
    366     {
    367         return;
    368     }
    369 
    370 
    371     GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
    372 
    373     switch (mInternalFormat)
    374     {
    375       case GL_ALPHA8_EXT:
    376         if (gl::supportsSSE2())
    377         {
    378             loadAlphaDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    379         }
    380         else
    381         {
    382             loadAlphaDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    383         }
    384         break;
    385       case GL_LUMINANCE8_EXT:
    386         loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
    387         break;
    388       case GL_ALPHA32F_EXT:
    389         loadAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    390         break;
    391       case GL_LUMINANCE32F_EXT:
    392         loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    393         break;
    394       case GL_ALPHA16F_EXT:
    395         loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    396         break;
    397       case GL_LUMINANCE16F_EXT:
    398         loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    399         break;
    400       case GL_LUMINANCE8_ALPHA8_EXT:
    401         loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
    402         break;
    403       case GL_LUMINANCE_ALPHA32F_EXT:
    404         loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    405         break;
    406       case GL_LUMINANCE_ALPHA16F_EXT:
    407         loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    408         break;
    409       case GL_RGB8_OES:
    410         loadRGBUByteDataToBGRX(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    411         break;
    412       case GL_RGB565:
    413         loadRGB565DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    414         break;
    415       case GL_RGBA8_OES:
    416         if (gl::supportsSSE2())
    417         {
    418             loadRGBAUByteDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    419         }
    420         else
    421         {
    422             loadRGBAUByteDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    423         }
    424         break;
    425       case GL_RGBA4:
    426         loadRGBA4444DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    427         break;
    428       case GL_RGB5_A1:
    429         loadRGBA5551DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    430         break;
    431       case GL_BGRA8_EXT:
    432         loadBGRADataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    433         break;
    434       // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
    435       case GL_RGB32F_EXT:
    436         loadRGBFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    437         break;
    438       case GL_RGB16F_EXT:
    439         loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    440         break;
    441       case GL_RGBA32F_EXT:
    442         loadRGBAFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    443         break;
    444       case GL_RGBA16F_EXT:
    445         loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
    446         break;
    447       default: UNREACHABLE();
    448     }
    449 
    450     unlock();
    451 }
    452 
    453 void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
    454                                 const void *input)
    455 {
    456     ASSERT(xoffset % 4 == 0);
    457     ASSERT(yoffset % 4 == 0);
    458 
    459     RECT lockRect = {
    460         xoffset, yoffset,
    461         xoffset + width, yoffset + height
    462     };
    463 
    464     D3DLOCKED_RECT locked;
    465     HRESULT result = lock(&locked, &lockRect);
    466     if (FAILED(result))
    467     {
    468         return;
    469     }
    470 
    471     GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
    472     GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
    473     int rows = inputSize / inputPitch;
    474     for (int i = 0; i < rows; ++i)
    475     {
    476         memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
    477     }
    478 
    479     unlock();
    480 }
    481 
    482 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
    483 void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    484 {
    485     RenderTarget9 *renderTarget = NULL;
    486     IDirect3DSurface9 *surface = NULL;
    487     gl::Renderbuffer *colorbuffer = source->getColorbuffer(0);
    488 
    489     if (colorbuffer)
    490     {
    491         renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
    492     }
    493 
    494     if (renderTarget)
    495     {
    496         surface = renderTarget->getSurface();
    497     }
    498 
    499     if (!surface)
    500     {
    501         ERR("Failed to retrieve the render target.");
    502         return gl::error(GL_OUT_OF_MEMORY);
    503     }
    504 
    505     IDirect3DDevice9 *device = mRenderer->getDevice();
    506 
    507     IDirect3DSurface9 *renderTargetData = NULL;
    508     D3DSURFACE_DESC description;
    509     surface->GetDesc(&description);
    510 
    511     HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
    512 
    513     if (FAILED(result))
    514     {
    515         ERR("Could not create matching destination surface.");
    516         surface->Release();
    517         return gl::error(GL_OUT_OF_MEMORY);
    518     }
    519 
    520     result = device->GetRenderTargetData(surface, renderTargetData);
    521 
    522     if (FAILED(result))
    523     {
    524         ERR("GetRenderTargetData unexpectedly failed.");
    525         renderTargetData->Release();
    526         surface->Release();
    527         return gl::error(GL_OUT_OF_MEMORY);
    528     }
    529 
    530     RECT sourceRect = {x, y, x + width, y + height};
    531     RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
    532 
    533     D3DLOCKED_RECT sourceLock = {0};
    534     result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
    535 
    536     if (FAILED(result))
    537     {
    538         ERR("Failed to lock the source surface (rectangle might be invalid).");
    539         renderTargetData->Release();
    540         surface->Release();
    541         return gl::error(GL_OUT_OF_MEMORY);
    542     }
    543 
    544     D3DLOCKED_RECT destLock = {0};
    545     result = lock(&destLock, &destRect);
    546 
    547     if (FAILED(result))
    548     {
    549         ERR("Failed to lock the destination surface (rectangle might be invalid).");
    550         renderTargetData->UnlockRect();
    551         renderTargetData->Release();
    552         surface->Release();
    553         return gl::error(GL_OUT_OF_MEMORY);
    554     }
    555 
    556     if (destLock.pBits && sourceLock.pBits)
    557     {
    558         unsigned char *source = (unsigned char*)sourceLock.pBits;
    559         unsigned char *dest = (unsigned char*)destLock.pBits;
    560 
    561         switch (description.Format)
    562         {
    563           case D3DFMT_X8R8G8B8:
    564           case D3DFMT_A8R8G8B8:
    565             switch(getD3DFormat())
    566             {
    567               case D3DFMT_X8R8G8B8:
    568               case D3DFMT_A8R8G8B8:
    569                 for(int y = 0; y < height; y++)
    570                 {
    571                     memcpy(dest, source, 4 * width);
    572 
    573                     source += sourceLock.Pitch;
    574                     dest += destLock.Pitch;
    575                 }
    576                 break;
    577               case D3DFMT_L8:
    578                 for(int y = 0; y < height; y++)
    579                 {
    580                     for(int x = 0; x < width; x++)
    581                     {
    582                         dest[x] = source[x * 4 + 2];
    583                     }
    584 
    585                     source += sourceLock.Pitch;
    586                     dest += destLock.Pitch;
    587                 }
    588                 break;
    589               case D3DFMT_A8L8:
    590                 for(int y = 0; y < height; y++)
    591                 {
    592                     for(int x = 0; x < width; x++)
    593                     {
    594                         dest[x * 2 + 0] = source[x * 4 + 2];
    595                         dest[x * 2 + 1] = source[x * 4 + 3];
    596                     }
    597 
    598                     source += sourceLock.Pitch;
    599                     dest += destLock.Pitch;
    600                 }
    601                 break;
    602               default:
    603                 UNREACHABLE();
    604             }
    605             break;
    606           case D3DFMT_R5G6B5:
    607             switch(getD3DFormat())
    608             {
    609               case D3DFMT_X8R8G8B8:
    610                 for(int y = 0; y < height; y++)
    611                 {
    612                     for(int x = 0; x < width; x++)
    613                     {
    614                         unsigned short rgb = ((unsigned short*)source)[x];
    615                         unsigned char red = (rgb & 0xF800) >> 8;
    616                         unsigned char green = (rgb & 0x07E0) >> 3;
    617                         unsigned char blue = (rgb & 0x001F) << 3;
    618                         dest[x + 0] = blue | (blue >> 5);
    619                         dest[x + 1] = green | (green >> 6);
    620                         dest[x + 2] = red | (red >> 5);
    621                         dest[x + 3] = 0xFF;
    622                     }
    623 
    624                     source += sourceLock.Pitch;
    625                     dest += destLock.Pitch;
    626                 }
    627                 break;
    628               case D3DFMT_L8:
    629                 for(int y = 0; y < height; y++)
    630                 {
    631                     for(int x = 0; x < width; x++)
    632                     {
    633                         unsigned char red = source[x * 2 + 1] & 0xF8;
    634                         dest[x] = red | (red >> 5);
    635                     }
    636 
    637                     source += sourceLock.Pitch;
    638                     dest += destLock.Pitch;
    639                 }
    640                 break;
    641               default:
    642                 UNREACHABLE();
    643             }
    644             break;
    645           case D3DFMT_A1R5G5B5:
    646             switch(getD3DFormat())
    647             {
    648               case D3DFMT_X8R8G8B8:
    649                 for(int y = 0; y < height; y++)
    650                 {
    651                     for(int x = 0; x < width; x++)
    652                     {
    653                         unsigned short argb = ((unsigned short*)source)[x];
    654                         unsigned char red = (argb & 0x7C00) >> 7;
    655                         unsigned char green = (argb & 0x03E0) >> 2;
    656                         unsigned char blue = (argb & 0x001F) << 3;
    657                         dest[x + 0] = blue | (blue >> 5);
    658                         dest[x + 1] = green | (green >> 5);
    659                         dest[x + 2] = red | (red >> 5);
    660                         dest[x + 3] = 0xFF;
    661                     }
    662 
    663                     source += sourceLock.Pitch;
    664                     dest += destLock.Pitch;
    665                 }
    666                 break;
    667               case D3DFMT_A8R8G8B8:
    668                 for(int y = 0; y < height; y++)
    669                 {
    670                     for(int x = 0; x < width; x++)
    671                     {
    672                         unsigned short argb = ((unsigned short*)source)[x];
    673                         unsigned char red = (argb & 0x7C00) >> 7;
    674                         unsigned char green = (argb & 0x03E0) >> 2;
    675                         unsigned char blue = (argb & 0x001F) << 3;
    676                         unsigned char alpha = (signed short)argb >> 15;
    677                         dest[x + 0] = blue | (blue >> 5);
    678                         dest[x + 1] = green | (green >> 5);
    679                         dest[x + 2] = red | (red >> 5);
    680                         dest[x + 3] = alpha;
    681                     }
    682 
    683                     source += sourceLock.Pitch;
    684                     dest += destLock.Pitch;
    685                 }
    686                 break;
    687               case D3DFMT_L8:
    688                 for(int y = 0; y < height; y++)
    689                 {
    690                     for(int x = 0; x < width; x++)
    691                     {
    692                         unsigned char red = source[x * 2 + 1] & 0x7C;
    693                         dest[x] = (red << 1) | (red >> 4);
    694                     }
    695 
    696                     source += sourceLock.Pitch;
    697                     dest += destLock.Pitch;
    698                 }
    699                 break;
    700               case D3DFMT_A8L8:
    701                 for(int y = 0; y < height; y++)
    702                 {
    703                     for(int x = 0; x < width; x++)
    704                     {
    705                         unsigned char red = source[x * 2 + 1] & 0x7C;
    706                         dest[x * 2 + 0] = (red << 1) | (red >> 4);
    707                         dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
    708                     }
    709 
    710                     source += sourceLock.Pitch;
    711                     dest += destLock.Pitch;
    712                 }
    713                 break;
    714               default:
    715                 UNREACHABLE();
    716             }
    717             break;
    718           default:
    719             UNREACHABLE();
    720         }
    721     }
    722 
    723     unlock();
    724     renderTargetData->UnlockRect();
    725 
    726     renderTargetData->Release();
    727     surface->Release();
    728 
    729     mDirty = true;
    730 }
    731 
    732 }