Home | History | Annotate | Download | only in d3d9
      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