1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/D3D9SurfaceImage.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,204 @@ 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 "D3D9SurfaceImage.h" 1.10 +#include "gfx2DGlue.h" 1.11 +#include "mozilla/layers/TextureD3D9.h" 1.12 +#include "mozilla/gfx/Types.h" 1.13 + 1.14 +namespace mozilla { 1.15 +namespace layers { 1.16 + 1.17 + 1.18 +D3D9SurfaceImage::D3D9SurfaceImage() 1.19 + : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE) 1.20 + , mSize(0, 0) 1.21 +{} 1.22 + 1.23 +D3D9SurfaceImage::~D3D9SurfaceImage() {} 1.24 + 1.25 +HRESULT 1.26 +D3D9SurfaceImage::SetData(const Data& aData) 1.27 +{ 1.28 + NS_ENSURE_TRUE(aData.mSurface, E_POINTER); 1.29 + HRESULT hr; 1.30 + RefPtr<IDirect3DSurface9> surface = aData.mSurface; 1.31 + 1.32 + RefPtr<IDirect3DDevice9> device; 1.33 + hr = surface->GetDevice(byRef(device)); 1.34 + NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); 1.35 + 1.36 + RefPtr<IDirect3D9> d3d9; 1.37 + hr = device->GetDirect3D(byRef(d3d9)); 1.38 + NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); 1.39 + 1.40 + D3DSURFACE_DESC desc; 1.41 + surface->GetDesc(&desc); 1.42 + // Ensure we can convert the textures format to RGB conversion 1.43 + // in StretchRect. Fail if we can't. 1.44 + hr = d3d9->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT, 1.45 + D3DDEVTYPE_HAL, 1.46 + desc.Format, 1.47 + D3DFMT_X8R8G8B8); 1.48 + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); 1.49 + 1.50 + // DXVA surfaces aren't created sharable, so we need to copy the surface 1.51 + // to a sharable texture to that it's accessible to the layer manager's 1.52 + // device. 1.53 + const nsIntRect& region = aData.mRegion; 1.54 + RefPtr<IDirect3DTexture9> texture; 1.55 + HANDLE shareHandle = nullptr; 1.56 + hr = device->CreateTexture(region.width, 1.57 + region.height, 1.58 + 1, 1.59 + D3DUSAGE_RENDERTARGET, 1.60 + D3DFMT_X8R8G8B8, 1.61 + D3DPOOL_DEFAULT, 1.62 + byRef(texture), 1.63 + &shareHandle); 1.64 + NS_ENSURE_TRUE(SUCCEEDED(hr) && shareHandle, hr); 1.65 + 1.66 + // Copy the image onto the texture, preforming YUV -> RGB conversion if necessary. 1.67 + RefPtr<IDirect3DSurface9> textureSurface; 1.68 + hr = texture->GetSurfaceLevel(0, byRef(textureSurface)); 1.69 + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); 1.70 + 1.71 + // Stash the surface description for later use. 1.72 + textureSurface->GetDesc(&mDesc); 1.73 + 1.74 + RECT src = { region.x, region.y, region.x+region.width, region.y+region.height }; 1.75 + hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE); 1.76 + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); 1.77 + 1.78 + // Flush the draw command now, so that by the time we come to draw this 1.79 + // image, we're less likely to need to wait for the draw operation to 1.80 + // complete. 1.81 + RefPtr<IDirect3DQuery9> query; 1.82 + hr = device->CreateQuery(D3DQUERYTYPE_EVENT, byRef(query)); 1.83 + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); 1.84 + hr = query->Issue(D3DISSUE_END); 1.85 + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); 1.86 + 1.87 + mTexture = texture; 1.88 + mShareHandle = shareHandle; 1.89 + mSize = gfx::IntSize(region.width, region.height); 1.90 + mQuery = query; 1.91 + 1.92 + return S_OK; 1.93 +} 1.94 + 1.95 +void 1.96 +D3D9SurfaceImage::EnsureSynchronized() 1.97 +{ 1.98 + if (!mQuery) { 1.99 + // Not setup, or already synchronized. 1.100 + return; 1.101 + } 1.102 + int iterations = 0; 1.103 + while (iterations < 10 && S_FALSE == mQuery->GetData(nullptr, 0, D3DGETDATA_FLUSH)) { 1.104 + Sleep(1); 1.105 + iterations++; 1.106 + } 1.107 + mQuery = nullptr; 1.108 +} 1.109 + 1.110 +HANDLE 1.111 +D3D9SurfaceImage::GetShareHandle() 1.112 +{ 1.113 + // Ensure the image has completed its synchronization, 1.114 + // and safe to used by the caller on another device. 1.115 + EnsureSynchronized(); 1.116 + return mShareHandle; 1.117 +} 1.118 + 1.119 +const D3DSURFACE_DESC& 1.120 +D3D9SurfaceImage::GetDesc() const 1.121 +{ 1.122 + return mDesc; 1.123 +} 1.124 + 1.125 +gfx::IntSize 1.126 +D3D9SurfaceImage::GetSize() 1.127 +{ 1.128 + return mSize; 1.129 +} 1.130 + 1.131 +TextureClient* 1.132 +D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient) 1.133 +{ 1.134 + EnsureSynchronized(); 1.135 + if (!mTextureClient) { 1.136 + RefPtr<SharedTextureClientD3D9> textureClient = 1.137 + new SharedTextureClientD3D9(gfx::SurfaceFormat::B8G8R8X8, TEXTURE_FLAGS_DEFAULT); 1.138 + textureClient->InitWith(mTexture, mShareHandle, mDesc); 1.139 + mTextureClient = textureClient; 1.140 + } 1.141 + return mTextureClient; 1.142 +} 1.143 + 1.144 +TemporaryRef<gfx::SourceSurface> 1.145 +D3D9SurfaceImage::GetAsSourceSurface() 1.146 +{ 1.147 + NS_ENSURE_TRUE(mTexture, nullptr); 1.148 + 1.149 + HRESULT hr; 1.150 + RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); 1.151 + 1.152 + if (!surface) { 1.153 + NS_WARNING("Failed to created SourceSurface for D3D9SurfaceImage."); 1.154 + return nullptr; 1.155 + } 1.156 + 1.157 + // Ensure that the texture is ready to be used. 1.158 + EnsureSynchronized(); 1.159 + 1.160 + // Readback the texture from GPU memory into system memory, so that 1.161 + // we can copy it into the Cairo image. This is expensive. 1.162 + RefPtr<IDirect3DSurface9> textureSurface; 1.163 + hr = mTexture->GetSurfaceLevel(0, byRef(textureSurface)); 1.164 + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); 1.165 + 1.166 + RefPtr<IDirect3DDevice9> device; 1.167 + hr = mTexture->GetDevice(byRef(device)); 1.168 + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); 1.169 + 1.170 + RefPtr<IDirect3DSurface9> systemMemorySurface; 1.171 + hr = device->CreateOffscreenPlainSurface(mDesc.Width, 1.172 + mDesc.Height, 1.173 + D3DFMT_X8R8G8B8, 1.174 + D3DPOOL_SYSTEMMEM, 1.175 + byRef(systemMemorySurface), 1.176 + 0); 1.177 + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); 1.178 + 1.179 + hr = device->GetRenderTargetData(textureSurface, systemMemorySurface); 1.180 + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); 1.181 + 1.182 + D3DLOCKED_RECT rect; 1.183 + hr = systemMemorySurface->LockRect(&rect, nullptr, 0); 1.184 + NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); 1.185 + 1.186 + gfx::DataSourceSurface::MappedSurface mappedSurface; 1.187 + if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { 1.188 + systemMemorySurface->UnlockRect(); 1.189 + return nullptr; 1.190 + } 1.191 + 1.192 + const unsigned char* src = (const unsigned char*)(rect.pBits); 1.193 + const unsigned srcPitch = rect.Pitch; 1.194 + for (int y = 0; y < mSize.height; y++) { 1.195 + memcpy(mappedSurface.mData + mappedSurface.mStride * y, 1.196 + (unsigned char*)(src) + srcPitch * y, 1.197 + mSize.width * 4); 1.198 + } 1.199 + 1.200 + systemMemorySurface->UnlockRect(); 1.201 + surface->Unmap(); 1.202 + 1.203 + return surface; 1.204 +} 1.205 + 1.206 +} /* layers */ 1.207 +} /* mozilla */