Home | History | Annotate | Download | only in renderer
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 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 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
      9 // the actual underlying resources of a Texture
     10 
     11 #include "libGLESv2/renderer/Renderer11.h"
     12 #include "libGLESv2/renderer/Image11.h"
     13 #include "libGLESv2/renderer/TextureStorage11.h"
     14 #include "libGLESv2/Framebuffer.h"
     15 #include "libGLESv2/Renderbuffer.h"
     16 
     17 #include "libGLESv2/main.h"
     18 #include "libGLESv2/utilities.h"
     19 #include "libGLESv2/renderer/renderer11_utils.h"
     20 #include "libGLESv2/renderer/generatemip.h"
     21 
     22 namespace rx
     23 {
     24 
     25 Image11::Image11()
     26 {
     27     mStagingTexture = NULL;
     28     mRenderer = NULL;
     29     mDXGIFormat = DXGI_FORMAT_UNKNOWN;
     30 }
     31 
     32 Image11::~Image11()
     33 {
     34     if (mStagingTexture)
     35     {
     36         mStagingTexture->Release();
     37     }
     38 }
     39 
     40 Image11 *Image11::makeImage11(Image *img)
     41 {
     42     ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
     43     return static_cast<rx::Image11*>(img);
     44 }
     45 
     46 void Image11::generateMipmap(Image11 *dest, Image11 *src)
     47 {
     48     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
     49     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
     50     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
     51 
     52     D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
     53     dest->map(D3D11_MAP_WRITE, &destMapped);
     54     src->map(D3D11_MAP_READ, &srcMapped);
     55 
     56     const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
     57     unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
     58 
     59     if (sourceData && destData)
     60     {
     61         switch (src->getDXGIFormat())
     62         {
     63           case DXGI_FORMAT_R8G8B8A8_UNORM:
     64           case DXGI_FORMAT_B8G8R8A8_UNORM:
     65             GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     66             break;
     67           case DXGI_FORMAT_A8_UNORM:
     68             GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     69             break;
     70           case DXGI_FORMAT_R8_UNORM:
     71             GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     72             break;
     73           case DXGI_FORMAT_R32G32B32A32_FLOAT:
     74             GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     75             break;
     76           case DXGI_FORMAT_R32G32B32_FLOAT:
     77             GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     78             break;
     79           case DXGI_FORMAT_R16G16B16A16_FLOAT:
     80             GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     81             break;
     82           case DXGI_FORMAT_R8G8_UNORM:
     83             GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     84             break;
     85           case DXGI_FORMAT_R16_FLOAT:
     86             GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     87             break;
     88           case DXGI_FORMAT_R16G16_FLOAT:
     89             GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     90             break;
     91           case DXGI_FORMAT_R32_FLOAT:
     92             GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     93             break;
     94           case DXGI_FORMAT_R32G32_FLOAT:
     95             GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
     96             break;
     97           default:
     98             UNREACHABLE();
     99             break;
    100         }
    101 
    102         dest->unmap();
    103         src->unmap();
    104     }
    105 
    106     dest->markDirty();
    107 }
    108 
    109 bool Image11::isDirty() const
    110 {
    111     return (mStagingTexture && mDirty);
    112 }
    113 
    114 bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    115 {
    116     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
    117     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height);
    118 }
    119 
    120 bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
    121 {
    122     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
    123     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height);
    124 }
    125 
    126 bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
    127 {
    128     if (mWidth != width ||
    129         mHeight != height ||
    130         mInternalFormat != internalformat ||
    131         forceRelease)
    132     {
    133         mRenderer = Renderer11::makeRenderer11(renderer);
    134 
    135         mWidth = width;
    136         mHeight = height;
    137         mInternalFormat = internalformat;
    138         // compute the d3d format that will be used
    139         mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
    140         mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
    141 
    142         if (mStagingTexture)
    143         {
    144             mStagingTexture->Release();
    145             mStagingTexture = NULL;
    146         }
    147 
    148         return true;
    149     }
    150 
    151     return false;
    152 }
    153 
    154 bool Image11::isRenderableFormat() const
    155 {
    156     return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
    157 }
    158 
    159 DXGI_FORMAT Image11::getDXGIFormat() const
    160 {
    161     // this should only happen if the image hasn't been redefined first
    162     // which would be a bug by the caller
    163     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
    164 
    165     return mDXGIFormat;
    166 }
    167 
    168 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
    169 // into the target pixel rectangle.
    170 void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
    171                        GLint unpackAlignment, const void *input)
    172 {
    173     D3D11_MAPPED_SUBRESOURCE mappedImage;
    174     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    175     if (FAILED(result))
    176     {
    177         ERR("Could not map image for loading.");
    178         return;
    179     }
    180 
    181     GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
    182     size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
    183     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
    184 
    185     switch (mInternalFormat)
    186     {
    187       case GL_ALPHA8_EXT:
    188         loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    189         break;
    190       case GL_LUMINANCE8_EXT:
    191         loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
    192         break;
    193       case GL_ALPHA32F_EXT:
    194         loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    195         break;
    196       case GL_LUMINANCE32F_EXT:
    197         loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    198         break;
    199       case GL_ALPHA16F_EXT:
    200         loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    201         break;
    202       case GL_LUMINANCE16F_EXT:
    203         loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    204         break;
    205       case GL_LUMINANCE8_ALPHA8_EXT:
    206         loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
    207         break;
    208       case GL_LUMINANCE_ALPHA32F_EXT:
    209         loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    210         break;
    211       case GL_LUMINANCE_ALPHA16F_EXT:
    212         loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    213         break;
    214       case GL_RGB8_OES:
    215         loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    216         break;
    217       case GL_RGB565:
    218         loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    219         break;
    220       case GL_RGBA8_OES:
    221         loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    222         break;
    223       case GL_RGBA4:
    224         loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    225         break;
    226       case GL_RGB5_A1:
    227         loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    228         break;
    229       case GL_BGRA8_EXT:
    230         loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    231         break;
    232       case GL_RGB32F_EXT:
    233         loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    234         break;
    235       case GL_RGB16F_EXT:
    236         loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    237         break;
    238       case GL_RGBA32F_EXT:
    239         loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    240         break;
    241       case GL_RGBA16F_EXT:
    242         loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
    243         break;
    244       default: UNREACHABLE();
    245     }
    246 
    247     unmap();
    248 }
    249 
    250 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
    251                                 const void *input)
    252 {
    253     ASSERT(xoffset % 4 == 0);
    254     ASSERT(yoffset % 4 == 0);
    255 
    256     D3D11_MAPPED_SUBRESOURCE mappedImage;
    257     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    258     if (FAILED(result))
    259     {
    260         ERR("Could not map image for loading.");
    261         return;
    262     }
    263 
    264     // Size computation assumes a 4x4 block compressed texture format
    265     size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
    266     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
    267 
    268     GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
    269     GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
    270     int rows = inputSize / inputPitch;
    271     for (int i = 0; i < rows; ++i)
    272     {
    273         memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
    274     }
    275 
    276     unmap();
    277 }
    278 
    279 void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
    280 {
    281     gl::Renderbuffer *colorbuffer = source->getReadColorbuffer();
    282 
    283     if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat)
    284     {
    285         // No conversion needed-- use copyback fastpath
    286         ID3D11Texture2D *colorBufferTexture = NULL;
    287         unsigned int subresourceIndex = 0;
    288 
    289         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
    290         {
    291             D3D11_TEXTURE2D_DESC textureDesc;
    292             colorBufferTexture->GetDesc(&textureDesc);
    293 
    294             ID3D11Device *device = mRenderer->getDevice();
    295             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    296 
    297             ID3D11Texture2D* srcTex = NULL;
    298             if (textureDesc.SampleDesc.Count > 1)
    299             {
    300                 D3D11_TEXTURE2D_DESC resolveDesc;
    301                 resolveDesc.Width = textureDesc.Width;
    302                 resolveDesc.Height = textureDesc.Height;
    303                 resolveDesc.MipLevels = 1;
    304                 resolveDesc.ArraySize = 1;
    305                 resolveDesc.Format = textureDesc.Format;
    306                 resolveDesc.SampleDesc.Count = 1;
    307                 resolveDesc.SampleDesc.Quality = 0;
    308                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
    309                 resolveDesc.BindFlags = 0;
    310                 resolveDesc.CPUAccessFlags = 0;
    311                 resolveDesc.MiscFlags = 0;
    312 
    313                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
    314                 if (FAILED(result))
    315                 {
    316                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
    317                     return;
    318                 }
    319 
    320                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
    321                 subresourceIndex = 0;
    322             }
    323             else
    324             {
    325                 srcTex = colorBufferTexture;
    326                 srcTex->AddRef();
    327             }
    328 
    329             D3D11_BOX srcBox;
    330             srcBox.left = x;
    331             srcBox.right = x + width;
    332             srcBox.top = y;
    333             srcBox.bottom = y + height;
    334             srcBox.front = 0;
    335             srcBox.back = 1;
    336 
    337             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
    338 
    339             srcTex->Release();
    340             colorBufferTexture->Release();
    341         }
    342     }
    343     else
    344     {
    345         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
    346         D3D11_MAPPED_SUBRESOURCE mappedImage;
    347         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
    348 
    349         // determine the offset coordinate into the destination buffer
    350         GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset;
    351         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset;
    352 
    353         mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat),
    354                               gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset);
    355 
    356         unmap();
    357     }
    358 }
    359 
    360 ID3D11Texture2D *Image11::getStagingTexture()
    361 {
    362     createStagingTexture();
    363 
    364     return mStagingTexture;
    365 }
    366 
    367 unsigned int Image11::getStagingSubresource()
    368 {
    369     createStagingTexture();
    370 
    371     return mStagingSubresource;
    372 }
    373 
    374 void Image11::createStagingTexture()
    375 {
    376     if (mStagingTexture)
    377     {
    378         return;
    379     }
    380 
    381     ID3D11Texture2D *newTexture = NULL;
    382     int lodOffset = 1;
    383     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
    384     ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
    385 
    386     if (mWidth != 0 && mHeight != 0)
    387     {
    388         GLsizei width = mWidth;
    389         GLsizei height = mHeight;
    390 
    391         // adjust size if needed for compressed textures
    392         gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset);
    393         ID3D11Device *device = mRenderer->getDevice();
    394 
    395         D3D11_TEXTURE2D_DESC desc;
    396         desc.Width = width;
    397         desc.Height = height;
    398         desc.MipLevels = lodOffset + 1;
    399         desc.ArraySize = 1;
    400         desc.Format = dxgiFormat;
    401         desc.SampleDesc.Count = 1;
    402         desc.SampleDesc.Quality = 0;
    403         desc.Usage = D3D11_USAGE_STAGING;
    404         desc.BindFlags = 0;
    405         desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    406         desc.MiscFlags = 0;
    407 
    408         HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
    409 
    410         if (FAILED(result))
    411         {
    412             ASSERT(result == E_OUTOFMEMORY);
    413             ERR("Creating image failed.");
    414             return gl::error(GL_OUT_OF_MEMORY);
    415         }
    416     }
    417 
    418     mStagingTexture = newTexture;
    419     mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
    420     mDirty = false;
    421 }
    422 
    423 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
    424 {
    425     createStagingTexture();
    426 
    427     HRESULT result = E_FAIL;
    428 
    429     if (mStagingTexture)
    430     {
    431         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    432         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
    433 
    434         // this can fail if the device is removed (from TDR)
    435         if (d3d11::isDeviceLostError(result))
    436         {
    437             mRenderer->notifyDeviceLost();
    438         }
    439         else if (SUCCEEDED(result))
    440         {
    441             mDirty = true;
    442         }
    443     }
    444 
    445     return result;
    446 }
    447 
    448 void Image11::unmap()
    449 {
    450     if (mStagingTexture)
    451     {
    452         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    453         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
    454     }
    455 }
    456 
    457 }
    458