1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/2d/SourceSurfaceD2D.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,303 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "SourceSurfaceD2D.h" 1.10 +#include "DrawTargetD2D.h" 1.11 +#include "Logging.h" 1.12 +#include "Tools.h" 1.13 + 1.14 +namespace mozilla { 1.15 +namespace gfx { 1.16 + 1.17 +SourceSurfaceD2D::SourceSurfaceD2D() 1.18 +{ 1.19 +} 1.20 + 1.21 +SourceSurfaceD2D::~SourceSurfaceD2D() 1.22 +{ 1.23 + if (mBitmap) { 1.24 + DrawTargetD2D::mVRAMUsageSS -= GetByteSize(); 1.25 + } 1.26 +} 1.27 + 1.28 +IntSize 1.29 +SourceSurfaceD2D::GetSize() const 1.30 +{ 1.31 + return mSize; 1.32 +} 1.33 + 1.34 +SurfaceFormat 1.35 +SourceSurfaceD2D::GetFormat() const 1.36 +{ 1.37 + return mFormat; 1.38 +} 1.39 + 1.40 +bool 1.41 +SourceSurfaceD2D::IsValid() const 1.42 +{ 1.43 + return mDevice == Factory::GetDirect3D10Device(); 1.44 +} 1.45 + 1.46 +TemporaryRef<DataSourceSurface> 1.47 +SourceSurfaceD2D::GetDataSurface() 1.48 +{ 1.49 + RefPtr<DataSourceSurfaceD2D> result = new DataSourceSurfaceD2D(this); 1.50 + if (result->IsValid()) { 1.51 + return result; 1.52 + } 1.53 + return nullptr; 1.54 +} 1.55 + 1.56 +bool 1.57 +SourceSurfaceD2D::InitFromData(unsigned char *aData, 1.58 + const IntSize &aSize, 1.59 + int32_t aStride, 1.60 + SurfaceFormat aFormat, 1.61 + ID2D1RenderTarget *aRT) 1.62 +{ 1.63 + HRESULT hr; 1.64 + 1.65 + mFormat = aFormat; 1.66 + mSize = aSize; 1.67 + 1.68 + if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() || 1.69 + (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) { 1.70 + gfxDebug() << "Bitmap does not fit in texture."; 1.71 + return false; 1.72 + } 1.73 + 1.74 + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); 1.75 + hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap)); 1.76 + 1.77 + if (FAILED(hr)) { 1.78 + gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hr; 1.79 + return false; 1.80 + } 1.81 + 1.82 + DrawTargetD2D::mVRAMUsageSS += GetByteSize(); 1.83 + mDevice = Factory::GetDirect3D10Device(); 1.84 + 1.85 + return true; 1.86 +} 1.87 + 1.88 +bool 1.89 +SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture, 1.90 + SurfaceFormat aFormat, 1.91 + ID2D1RenderTarget *aRT) 1.92 +{ 1.93 + HRESULT hr; 1.94 + 1.95 + RefPtr<IDXGISurface> surf; 1.96 + 1.97 + hr = aTexture->QueryInterface((IDXGISurface**)&surf); 1.98 + 1.99 + if (FAILED(hr)) { 1.100 + gfxWarning() << "Failed to QI texture to surface. Code: " << hr; 1.101 + return false; 1.102 + } 1.103 + 1.104 + D3D10_TEXTURE2D_DESC desc; 1.105 + aTexture->GetDesc(&desc); 1.106 + 1.107 + mSize = IntSize(desc.Width, desc.Height); 1.108 + mFormat = aFormat; 1.109 + 1.110 + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); 1.111 + hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); 1.112 + 1.113 + if (FAILED(hr)) { 1.114 + gfxWarning() << "Failed to create SharedBitmap. Code: " << hr; 1.115 + return false; 1.116 + } 1.117 + 1.118 + aTexture->GetDevice(byRef(mDevice)); 1.119 + DrawTargetD2D::mVRAMUsageSS += GetByteSize(); 1.120 + 1.121 + return true; 1.122 +} 1.123 + 1.124 +uint32_t 1.125 +SourceSurfaceD2D::GetByteSize() const 1.126 +{ 1.127 + return mSize.width * mSize.height * BytesPerPixel(mFormat); 1.128 +} 1.129 + 1.130 +DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface) 1.131 + : mTexture(nullptr) 1.132 + , mFormat(aSourceSurface->mFormat) 1.133 + , mSize(aSourceSurface->mSize) 1.134 + , mMapped(false) 1.135 +{ 1.136 + // We allocate ourselves a regular D3D surface (sourceTexture) and paint the 1.137 + // D2D bitmap into it via a DXGI render target. Then we need to copy 1.138 + // sourceTexture into a staging texture (mTexture), which we will lazily map 1.139 + // to get the data. 1.140 + 1.141 + CD3D10_TEXTURE2D_DESC desc(DXGIFormat(mFormat), mSize.width, mSize.height); 1.142 + desc.MipLevels = 1; 1.143 + desc.Usage = D3D10_USAGE_DEFAULT; 1.144 + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; 1.145 + RefPtr<ID3D10Texture2D> sourceTexture; 1.146 + HRESULT hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, 1.147 + byRef(sourceTexture)); 1.148 + if (FAILED(hr)) { 1.149 + gfxWarning() << "Failed to create texture. Code: " << hr; 1.150 + return; 1.151 + } 1.152 + 1.153 + RefPtr<IDXGISurface> dxgiSurface; 1.154 + hr = sourceTexture->QueryInterface((IDXGISurface**)byRef(dxgiSurface)); 1.155 + if (FAILED(hr)) { 1.156 + gfxWarning() << "Failed to create DXGI surface. Code: " << hr; 1.157 + return; 1.158 + } 1.159 + 1.160 + D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties( 1.161 + D2D1_RENDER_TARGET_TYPE_DEFAULT, 1.162 + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)); 1.163 + 1.164 + RefPtr<ID2D1RenderTarget> renderTarget; 1.165 + hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface, 1.166 + &rtProps, 1.167 + byRef(renderTarget)); 1.168 + if (FAILED(hr)) { 1.169 + gfxWarning() << "Failed to create render target. Code: " << hr; 1.170 + return; 1.171 + } 1.172 + 1.173 + renderTarget->BeginDraw(); 1.174 + renderTarget->Clear(D2D1::ColorF(0, 0.0f)); 1.175 + renderTarget->DrawBitmap(aSourceSurface->mBitmap, 1.176 + D2D1::RectF(0, 0, 1.177 + Float(mSize.width), 1.178 + Float(mSize.height))); 1.179 + hr = renderTarget->EndDraw(); 1.180 + if (FAILED(hr)) { 1.181 + gfxWarning() << "Failed to draw bitmap. Code: " << hr; 1.182 + return; 1.183 + } 1.184 + 1.185 + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE; 1.186 + desc.Usage = D3D10_USAGE_STAGING; 1.187 + desc.BindFlags = 0; 1.188 + hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture)); 1.189 + if (FAILED(hr)) { 1.190 + gfxWarning() << "Failed to create staging texture. Code: " << hr; 1.191 + mTexture = nullptr; 1.192 + return; 1.193 + } 1.194 + 1.195 + aSourceSurface->mDevice->CopyResource(mTexture, sourceTexture); 1.196 +} 1.197 + 1.198 +DataSourceSurfaceD2D::~DataSourceSurfaceD2D() 1.199 +{ 1.200 + if (mMapped) { 1.201 + mTexture->Unmap(0); 1.202 + } 1.203 +} 1.204 + 1.205 +unsigned char* 1.206 +DataSourceSurfaceD2D::GetData() 1.207 +{ 1.208 + EnsureMappedTexture(); 1.209 + if (!mMapped) { 1.210 + return nullptr; 1.211 + } 1.212 + 1.213 + return reinterpret_cast<unsigned char*>(mData.pData); 1.214 +} 1.215 + 1.216 +int32_t 1.217 +DataSourceSurfaceD2D::Stride() 1.218 +{ 1.219 + EnsureMappedTexture(); 1.220 + if (!mMapped) { 1.221 + return 0; 1.222 + } 1.223 + 1.224 + return mData.RowPitch; 1.225 +} 1.226 + 1.227 +IntSize 1.228 +DataSourceSurfaceD2D::GetSize() const 1.229 +{ 1.230 + return mSize; 1.231 +} 1.232 + 1.233 +SurfaceFormat 1.234 +DataSourceSurfaceD2D::GetFormat() const 1.235 +{ 1.236 + return mFormat; 1.237 +} 1.238 + 1.239 +bool 1.240 +DataSourceSurfaceD2D::Map(MapType aMapType, MappedSurface *aMappedSurface) 1.241 +{ 1.242 + // DataSourceSurfaces used with the new Map API should not be used with GetData!! 1.243 + MOZ_ASSERT(!mMapped); 1.244 + MOZ_ASSERT(!mIsMapped); 1.245 + 1.246 + if (!mTexture) { 1.247 + return false; 1.248 + } 1.249 + 1.250 + D3D10_MAP mapType; 1.251 + 1.252 + if (aMapType == MapType::READ) { 1.253 + mapType = D3D10_MAP_READ; 1.254 + } else if (aMapType == MapType::WRITE) { 1.255 + mapType = D3D10_MAP_WRITE; 1.256 + } else { 1.257 + mapType = D3D10_MAP_READ_WRITE; 1.258 + } 1.259 + 1.260 + D3D10_MAPPED_TEXTURE2D map; 1.261 + 1.262 + HRESULT hr = mTexture->Map(0, mapType, 0, &map); 1.263 + 1.264 + if (FAILED(hr)) { 1.265 + gfxWarning() << "Texture map failed with code: " << hr; 1.266 + return false; 1.267 + } 1.268 + 1.269 + aMappedSurface->mData = (uint8_t*)map.pData; 1.270 + aMappedSurface->mStride = map.RowPitch; 1.271 + mIsMapped = true; 1.272 + 1.273 + return true; 1.274 +} 1.275 + 1.276 +void 1.277 +DataSourceSurfaceD2D::Unmap() 1.278 +{ 1.279 + MOZ_ASSERT(mIsMapped); 1.280 + 1.281 + mIsMapped = false; 1.282 + mTexture->Unmap(0); 1.283 +} 1.284 + 1.285 +void 1.286 +DataSourceSurfaceD2D::EnsureMappedTexture() 1.287 +{ 1.288 + // Do not use GetData() after having used Map! 1.289 + MOZ_ASSERT(!mIsMapped); 1.290 + 1.291 + if (mMapped || 1.292 + !mTexture) { 1.293 + return; 1.294 + } 1.295 + 1.296 + HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mData); 1.297 + if (FAILED(hr)) { 1.298 + gfxWarning() << "Failed to map texture. Code: " << hr; 1.299 + mTexture = nullptr; 1.300 + } else { 1.301 + mMapped = true; 1.302 + } 1.303 +} 1.304 + 1.305 +} 1.306 +}