blob: cc969f604f92d5af879c8f451db2ba74c833404e [file] [log] [blame]
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +00001//
2// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.com31b13e12012-11-28 19:34:30 +00007// TextureStorage.cpp: Implements the abstract rx::TextureStorage class and its concrete derived
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +00008// classes TextureStorage2D and TextureStorageCubeMap, which act as the interface to the
9// D3D-side texture.
10
11#include "libGLESv2/main.h"
12#include "libGLESv2/renderer/TextureStorage.h"
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000013#include "libGLESv2/renderer/SwapChain9.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000014#include "libGLESv2/renderer/Blit.h"
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000015
daniel@transgaming.comd8e36562012-10-31 19:52:19 +000016#include "libGLESv2/renderer/renderer9_utils.h"
17
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000018#include "common/debug.h"
19
daniel@transgaming.com31b13e12012-11-28 19:34:30 +000020namespace rx
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000021{
22unsigned int TextureStorage::mCurrentTextureSerial = 1;
23
daniel@transgaming.com31b13e12012-11-28 19:34:30 +000024TextureStorage::TextureStorage(Renderer9 *renderer, DWORD usage)
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000025 : mD3DUsage(usage),
daniel@transgaming.coma9571682012-11-28 19:33:08 +000026 mD3DPool(renderer->getTexturePool(usage)),
daniel@transgaming.com70062c92012-11-28 19:32:30 +000027 mRenderer(renderer),
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000028 mTextureSerial(issueTextureSerial()),
29 mLodOffset(0)
30{
31}
32
33TextureStorage::~TextureStorage()
34{
35}
36
daniel@transgaming.comdf14c762012-10-31 19:51:48 +000037DWORD TextureStorage::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
38{
39 DWORD d3dusage = 0;
40
41 if (d3dfmt == D3DFMT_INTZ)
42 {
43 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
44 }
45 else if(forceRenderable || (TextureStorage::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
46 {
47 d3dusage |= D3DUSAGE_RENDERTARGET;
48 }
49 return d3dusage;
50}
51
52bool TextureStorage::IsTextureFormatRenderable(D3DFORMAT format)
53{
54 if (format == D3DFMT_INTZ)
55 {
56 return true;
57 }
58 switch(format)
59 {
60 case D3DFMT_L8:
61 case D3DFMT_A8L8:
62 case D3DFMT_DXT1:
63 case D3DFMT_DXT3:
64 case D3DFMT_DXT5:
65 return false;
66 case D3DFMT_A8R8G8B8:
67 case D3DFMT_X8R8G8B8:
68 case D3DFMT_A16B16G16R16F:
69 case D3DFMT_A32B32G32R32F:
70 return true;
71 default:
72 UNREACHABLE();
73 }
74
75 return false;
76}
77
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +000078bool TextureStorage::isRenderTarget() const
79{
80 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
81}
82
83bool TextureStorage::isManaged() const
84{
85 return (mD3DPool == D3DPOOL_MANAGED);
86}
87
88D3DPOOL TextureStorage::getPool() const
89{
90 return mD3DPool;
91}
92
93DWORD TextureStorage::getUsage() const
94{
95 return mD3DUsage;
96}
97
98unsigned int TextureStorage::getTextureSerial() const
99{
100 return mTextureSerial;
101}
102
103unsigned int TextureStorage::issueTextureSerial()
104{
105 return mCurrentTextureSerial++;
106}
107
108int TextureStorage::getLodOffset() const
109{
110 return mLodOffset;
111}
112
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000113int TextureStorage::levelCount()
114{
115 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
116}
117
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000118TextureStorage2D::TextureStorage2D(Renderer9 *renderer, rx::SwapChain9 *swapchain) : TextureStorage(renderer, D3DUSAGE_RENDERTARGET), mRenderTargetSerial(gl::RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000119{
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000120 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000121 mTexture = surfaceTexture;
122}
123
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000124TextureStorage2D::TextureStorage2D(Renderer9 *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000125 : TextureStorage(renderer, GetTextureUsage(renderer->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000126 mRenderTargetSerial(gl::RenderbufferStorage::issueSerial())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000127{
128 mTexture = NULL;
129 // if the width or height is not positive this should be treated as an incomplete texture
130 // we handle that here by skipping the d3d texture creation
131 if (width > 0 && height > 0)
132 {
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000133 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000134 gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000135 HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000136 renderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000137
138 if (FAILED(result))
139 {
140 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
141 error(GL_OUT_OF_MEMORY);
142 }
143 }
144}
145
146TextureStorage2D::~TextureStorage2D()
147{
148 if (mTexture)
149 {
150 mTexture->Release();
151 }
152}
153
154// Increments refcount on surface.
155// caller must Release() the returned surface
156IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty)
157{
158 IDirect3DSurface9 *surface = NULL;
159
160 if (mTexture)
161 {
162 HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
163 ASSERT(SUCCEEDED(result));
164
165 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
166 if (level != 0 && isManaged() && dirty)
167 {
168 mTexture->AddDirtyRect(NULL);
169 }
170 }
171
172 return surface;
173}
174
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000175void TextureStorage2D::generateMipmap(int level)
176{
177 IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
178 IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
179
180 if (upper != NULL && lower != NULL)
181 {
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000182 mRenderer->boxFilter(upper, lower);
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000183 }
184
185 if (upper != NULL) upper->Release();
186 if (lower != NULL) lower->Release();
187}
188
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000189IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
190{
191 return mTexture;
192}
193
194unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
195{
196 return mRenderTargetSerial;
197}
198
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000199TextureStorageCubeMap::TextureStorageCubeMap(Renderer9 *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000200 : TextureStorage(renderer, GetTextureUsage(renderer->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)),
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000201 mFirstRenderTargetSerial(gl::RenderbufferStorage::issueCubeSerials())
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000202{
203 mTexture = NULL;
204 // if the size is not positive this should be treated as an incomplete texture
205 // we handle that here by skipping the d3d texture creation
206 if (size > 0)
207 {
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000208 IDirect3DDevice9 *device = renderer->getDevice();
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000209 int height = size;
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000210 gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000211 HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
daniel@transgaming.coma9571682012-11-28 19:33:08 +0000212 renderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000213
214 if (FAILED(result))
215 {
216 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
217 error(GL_OUT_OF_MEMORY);
218 }
219 }
220}
221
222TextureStorageCubeMap::~TextureStorageCubeMap()
223{
224 if (mTexture)
225 {
226 mTexture->Release();
227 }
228}
229
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000230// Increments refcount on surface.
231// caller must Release() the returned surface
232IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
233{
234 IDirect3DSurface9 *surface = NULL;
235
236 if (mTexture)
237 {
daniel@transgaming.com682a37c2012-11-28 19:34:44 +0000238 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000239 HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
240 ASSERT(SUCCEEDED(result));
241
242 // With managed textures the driver needs to be informed of updates to the lower mipmap levels
243 if (level != 0 && isManaged() && dirty)
244 {
245 mTexture->AddDirtyRect(face, NULL);
246 }
247 }
248
249 return surface;
250}
251
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000252void TextureStorageCubeMap::generateMipmap(int face, int level)
253{
254 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
255 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
256
257 if (upper != NULL && lower != NULL)
258 {
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000259 mRenderer->boxFilter(upper, lower);
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000260 }
261
262 if (upper != NULL) upper->Release();
263 if (lower != NULL) lower->Release();
264}
265
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000266IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
267{
268 return mTexture;
269}
270
271unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
272{
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000273 return mFirstRenderTargetSerial + gl::TextureCubeMap::faceIndex(target);
daniel@transgaming.comb5e1a272012-10-31 19:10:00 +0000274}
275
276}