Creates Image11 class

TRAC #22208

Author: Shannon Woods
Signed-off-by: Geoff Lang
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1592 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Image11.cpp b/src/libGLESv2/renderer/Image11.cpp
new file mode 100644
index 0000000..68b7ba6
--- /dev/null
+++ b/src/libGLESv2/renderer/Image11.cpp
@@ -0,0 +1,289 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image11.h: Implements the rx::Image11 class, which acts as the interface to
+// the actual underlying resources of a Texture
+
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/renderer/Image11.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/renderer/renderer11_utils.h"
+
+namespace rx
+{
+
+Image11::Image11()
+{
+    mStagingTexture = NULL;
+    mRenderer = NULL;
+    mDXGIFormat = DXGI_FORMAT_UNKNOWN;
+}
+
+Image11::~Image11()
+{
+    if (mStagingTexture)
+    {
+        mStagingTexture->Release();
+    }
+}
+
+Image11 *Image11::makeImage11(Image *img)
+{
+    ASSERT(dynamic_cast<rx::Image11*>(img) != NULL);
+    return static_cast<rx::Image11*>(img);
+}
+
+bool Image11::isDirty() const
+{
+    return (mStagingTexture && mDirty);
+}
+
+bool Image11::updateSurface(TextureStorage2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+    // TODO - relies on TextureStorage11 implementation
+    UNIMPLEMENTED();
+    return false;
+}
+
+bool Image11::updateSurface(TextureStorageCubeMap *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+    // TODO - relies on TextureStorage11 implementation
+    UNIMPLEMENTED();
+    return false;
+}
+
+bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
+{
+    if (mWidth != width ||
+        mHeight != height ||
+        mInternalFormat != internalformat ||
+        forceRelease)
+    {
+        mRenderer = Renderer11::makeRenderer11(renderer);
+
+        mWidth = width;
+        mHeight = height;
+        mInternalFormat = internalformat;
+        // compute the d3d format that will be used
+        mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
+        mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
+
+        if (mStagingTexture)
+        {
+            mStagingTexture->Release();
+            mStagingTexture = NULL;
+        }
+        
+        return true;
+    }
+
+    return false;
+}
+
+bool Image11::isRenderableFormat() const
+{
+    // TODO - relies on TextureStorage11 implementation
+    UNIMPLEMENTED();
+    return false;
+}
+
+DXGI_FORMAT Image11::getDXGIFormat() const
+{
+    // this should only happen if the image hasn't been redefined first
+    // which would be a bug by the caller
+    ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
+
+    return mDXGIFormat;
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle.
+void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                       GLint unpackAlignment, const void *input)
+{
+    D3D11_MAPPED_SUBRESOURCE mappedImage;
+    HRESULT result = map(&mappedImage);
+    if (FAILED(result))
+    {
+        ERR("Could not map image for loading.");
+        return;
+    }
+    
+    GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
+    size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
+    void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
+
+    switch (mInternalFormat)
+    {
+      case GL_ALPHA8_EXT:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_LUMINANCE8_EXT:
+        loadLuminanceData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
+        break;
+      case GL_ALPHA32F_EXT:
+        loadAlphaFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_LUMINANCE32F_EXT:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_ALPHA16F_EXT:
+        loadAlphaHalfFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_LUMINANCE16F_EXT:
+        loadLuminanceHalfFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_LUMINANCE8_ALPHA8_EXT:
+        loadLuminanceAlphaData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
+        break;
+      case GL_LUMINANCE_ALPHA32F_EXT:
+        loadLuminanceAlphaFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_LUMINANCE_ALPHA16F_EXT:
+        loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_RGB8_OES:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_RGB565:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_RGBA8_OES:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_RGBA4:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_RGB5_A1:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_BGRA8_EXT:
+        loadBGRAData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_RGB32F_EXT:
+        UNIMPLEMENTED(); // TODO - new function for D3D11-supported formats
+        break;
+      case GL_RGB16F_EXT:
+        loadRGBHalfFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_RGBA32F_EXT:
+        loadRGBAFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      case GL_RGBA16F_EXT:
+        loadRGBAHalfFloatData(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+        break;
+      default: UNREACHABLE(); 
+    }
+
+    unmap();
+}
+
+void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                                const void *input)
+{
+    ASSERT(xoffset % 4 == 0);
+    ASSERT(yoffset % 4 == 0);
+
+    D3D11_MAPPED_SUBRESOURCE mappedImage;
+    HRESULT result = map(&mappedImage);
+    if (FAILED(result))
+    {
+        ERR("Could not map image for loading.");
+        return;
+    }
+
+    // Size computation assumes a 4x4 block compressed texture format
+    size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
+    void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
+
+    GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
+    GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
+    int rows = inputSize / inputPitch;
+    for (int i = 0; i < rows; ++i)
+    {
+        memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
+    }
+
+    unmap();
+}
+
+void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+{
+    // TODO
+    UNIMPLEMENTED();
+}
+
+void Image11::createStagingTexture()
+{
+    if (mStagingTexture)
+    {
+        return;
+    }
+
+    ID3D11Texture2D *newTexture = NULL;
+    const DXGI_FORMAT dxgiFormat = getDXGIFormat();
+    ASSERT(dxgiFormat != DXGI_FORMAT_D24_UNORM_S8_UINT); // We should never get here for depth textures
+
+    if (mWidth != 0 && mHeight != 0)
+    {
+        ID3D11Device *device = mRenderer->getDevice();
+
+        D3D11_TEXTURE2D_DESC desc;
+        desc.Width = mWidth;
+        desc.Height = mHeight;
+        desc.MipLevels = desc.ArraySize = 1;
+        desc.Format = dxgiFormat;
+        desc.SampleDesc.Count = 1;
+        desc.SampleDesc.Quality = 0;
+        desc.Usage = D3D11_USAGE_STAGING;
+        desc.BindFlags = 0;
+        desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+        desc.MiscFlags = 0;
+
+        HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
+
+        if (FAILED(result))
+        {
+            ASSERT(result == E_OUTOFMEMORY);
+            ERR("Creating image failed.");
+            return error(GL_OUT_OF_MEMORY);
+        }
+    }
+
+    mStagingTexture = newTexture;
+    mDirty = false;
+}
+
+HRESULT Image11::map(D3D11_MAPPED_SUBRESOURCE *map)
+{
+    createStagingTexture();
+
+    HRESULT result = D3DERR_INVALIDCALL;
+
+    if (mStagingTexture)
+    {
+        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+        result = deviceContext->Map(mStagingTexture, 0, D3D11_MAP_WRITE, 0, map);
+        ASSERT(SUCCEEDED(result));
+
+        mDirty = true;
+    }
+
+    return result;
+}
+
+void Image11::unmap()
+{
+    if (mStagingTexture)
+    {
+        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+        deviceContext->Unmap(mStagingTexture, 0);
+    }
+}
+
+}