1/* 2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22 23#include "c99_alloca.h" 24 25#include "device9.h" 26#include "cubetexture9.h" 27#include "nine_helpers.h" 28#include "nine_pipe.h" 29 30#define DBG_CHANNEL DBG_CUBETEXTURE 31 32 33static HRESULT 34NineCubeTexture9_ctor( struct NineCubeTexture9 *This, 35 struct NineUnknownParams *pParams, 36 UINT EdgeLength, UINT Levels, 37 DWORD Usage, 38 D3DFORMAT Format, 39 D3DPOOL Pool, 40 HANDLE *pSharedHandle ) 41{ 42 struct pipe_resource *info = &This->base.base.info; 43 struct pipe_screen *screen = pParams->device->screen; 44 enum pipe_format pf; 45 unsigned i, l, f, offset, face_size = 0; 46 unsigned *level_offsets = NULL; 47 D3DSURFACE_DESC sfdesc; 48 void *p; 49 HRESULT hr; 50 51 DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d " 52 "Format=%d Pool=%d pSharedHandle=%p\n", 53 This, pParams, EdgeLength, Levels, Usage, 54 Format, Pool, pSharedHandle); 55 56 user_assert(EdgeLength, D3DERR_INVALIDCALL); 57 58 /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */ 59 user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ 60 61 user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || 62 (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); 63 64 if (Usage & D3DUSAGE_AUTOGENMIPMAP) 65 Levels = 0; 66 67 pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_CUBE, 0, 68 PIPE_BIND_SAMPLER_VIEW, FALSE, 69 Pool == D3DPOOL_SCRATCH); 70 71 if (pf == PIPE_FORMAT_NONE) 72 return D3DERR_INVALIDCALL; 73 74 if (compressed_format(Format)) { 75 const unsigned w = util_format_get_blockwidth(pf); 76 const unsigned h = util_format_get_blockheight(pf); 77 78 user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL); 79 } 80 81 info->screen = pParams->device->screen; 82 info->target = PIPE_TEXTURE_CUBE; 83 info->format = pf; 84 info->width0 = EdgeLength; 85 info->height0 = EdgeLength; 86 info->depth0 = 1; 87 if (Levels) 88 info->last_level = Levels - 1; 89 else 90 info->last_level = util_logbase2(EdgeLength); 91 info->array_size = 6; 92 info->nr_samples = 0; 93 info->nr_storage_samples = 0; 94 info->bind = PIPE_BIND_SAMPLER_VIEW; 95 info->usage = PIPE_USAGE_DEFAULT; 96 info->flags = 0; 97 98 if (Usage & D3DUSAGE_RENDERTARGET) 99 info->bind |= PIPE_BIND_RENDER_TARGET; 100 if (Usage & D3DUSAGE_DEPTHSTENCIL) 101 info->bind |= PIPE_BIND_DEPTH_STENCIL; 102 103 if (Usage & D3DUSAGE_DYNAMIC) { 104 info->usage = PIPE_USAGE_DYNAMIC; 105 } 106 if (Usage & D3DUSAGE_SOFTWAREPROCESSING) 107 DBG("Application asked for Software Vertex Processing, " 108 "but this is unimplemented\n"); 109 110 if (Pool != D3DPOOL_DEFAULT) { 111 level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); 112 face_size = nine_format_get_size_and_offsets(pf, level_offsets, 113 EdgeLength, EdgeLength, 114 info->last_level); 115 This->managed_buffer = align_calloc(6 * face_size, 32); 116 if (!This->managed_buffer) 117 return E_OUTOFMEMORY; 118 } 119 120 This->surfaces = CALLOC(6 * (info->last_level + 1), sizeof(*This->surfaces)); 121 if (!This->surfaces) 122 return E_OUTOFMEMORY; 123 124 hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_CUBETEXTURE, 125 Format, Pool, Usage); 126 if (FAILED(hr)) 127 return hr; 128 This->base.pstype = 2; 129 130 /* Create all the surfaces right away. 131 * They manage backing storage, and transfers (LockRect) are deferred 132 * to them. 133 */ 134 sfdesc.Format = Format; 135 sfdesc.Type = D3DRTYPE_SURFACE; 136 sfdesc.Usage = Usage; 137 sfdesc.Pool = Pool; 138 sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; 139 sfdesc.MultiSampleQuality = 0; 140 /* We allocate the memory for the surfaces as continous blocks. 141 * This is the expected behaviour, however we haven't tested for 142 * cube textures in which order the faces/levels should be in memory 143 */ 144 for (f = 0; f < 6; f++) { 145 offset = f * face_size; 146 for (l = 0; l <= info->last_level; l++) { 147 sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l); 148 p = This->managed_buffer ? This->managed_buffer + offset + 149 level_offsets[l] : NULL; 150 151 hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), 152 This->base.base.resource, p, D3DRTYPE_CUBETEXTURE, 153 l, f, &sfdesc, &This->surfaces[f + 6 * l]); 154 if (FAILED(hr)) 155 return hr; 156 } 157 } 158 159 for (i = 0; i < 6; ++i) { 160 /* Textures start initially dirty */ 161 This->dirty_rect[i].width = EdgeLength; 162 This->dirty_rect[i].height = EdgeLength; 163 This->dirty_rect[i].depth = 1; 164 } 165 166 return D3D_OK; 167} 168 169static void 170NineCubeTexture9_dtor( struct NineCubeTexture9 *This ) 171{ 172 unsigned i; 173 174 DBG("This=%p\n", This); 175 176 if (This->surfaces) { 177 for (i = 0; i < (This->base.base.info.last_level + 1) * 6; ++i) 178 NineUnknown_Destroy(&This->surfaces[i]->base.base); 179 FREE(This->surfaces); 180 } 181 182 if (This->managed_buffer) 183 align_free(This->managed_buffer); 184 185 NineBaseTexture9_dtor(&This->base); 186} 187 188HRESULT NINE_WINAPI 189NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, 190 UINT Level, 191 D3DSURFACE_DESC *pDesc ) 192{ 193 DBG("This=%p Level=%u pDesc=%p\n", This, Level, pDesc); 194 195 user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 196 user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 197 D3DERR_INVALIDCALL); 198 199 *pDesc = This->surfaces[Level * 6]->desc; 200 201 return D3D_OK; 202} 203 204HRESULT NINE_WINAPI 205NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, 206 D3DCUBEMAP_FACES FaceType, 207 UINT Level, 208 IDirect3DSurface9 **ppCubeMapSurface ) 209{ 210 const unsigned s = Level * 6 + FaceType; 211 212 DBG("This=%p FaceType=%d Level=%u ppCubeMapSurface=%p\n", 213 This, FaceType, Level, ppCubeMapSurface); 214 215 user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 216 user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 217 D3DERR_INVALIDCALL); 218 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 219 220 NineUnknown_AddRef(NineUnknown(This->surfaces[s])); 221 *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s]; 222 223 return D3D_OK; 224} 225 226HRESULT NINE_WINAPI 227NineCubeTexture9_LockRect( struct NineCubeTexture9 *This, 228 D3DCUBEMAP_FACES FaceType, 229 UINT Level, 230 D3DLOCKED_RECT *pLockedRect, 231 const RECT *pRect, 232 DWORD Flags ) 233{ 234 const unsigned s = Level * 6 + FaceType; 235 236 DBG("This=%p FaceType=%d Level=%u pLockedRect=%p pRect=%p Flags=%d\n", 237 This, FaceType, Level, pLockedRect, pRect, Flags); 238 239 user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 240 user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 241 D3DERR_INVALIDCALL); 242 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 243 244 return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags); 245} 246 247HRESULT NINE_WINAPI 248NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, 249 D3DCUBEMAP_FACES FaceType, 250 UINT Level ) 251{ 252 const unsigned s = Level * 6 + FaceType; 253 254 DBG("This=%p FaceType=%d Level=%u\n", This, FaceType, Level); 255 256 user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 257 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 258 259 return NineSurface9_UnlockRect(This->surfaces[s]); 260} 261 262HRESULT NINE_WINAPI 263NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, 264 D3DCUBEMAP_FACES FaceType, 265 const RECT *pDirtyRect ) 266{ 267 DBG("This=%p FaceType=%d pDirtyRect=%p\n", This, FaceType, pDirtyRect); 268 269 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 270 271 if (This->base.base.pool != D3DPOOL_MANAGED) { 272 if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { 273 This->base.dirty_mip = TRUE; 274 BASETEX_REGISTER_UPDATE(&This->base); 275 } 276 return D3D_OK; 277 } 278 279 if (This->base.base.pool == D3DPOOL_MANAGED) { 280 This->base.managed.dirty = TRUE; 281 BASETEX_REGISTER_UPDATE(&This->base); 282 } 283 284 if (!pDirtyRect) { 285 u_box_origin_2d(This->base.base.info.width0, 286 This->base.base.info.height0, 287 &This->dirty_rect[FaceType]); 288 } else { 289 if (This->dirty_rect[FaceType].width == 0) { 290 rect_to_pipe_box_clamp(&This->dirty_rect[FaceType], pDirtyRect); 291 } else { 292 struct pipe_box box; 293 rect_to_pipe_box_clamp(&box, pDirtyRect); 294 u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType], 295 &box); 296 } 297 (void) u_box_clip_2d(&This->dirty_rect[FaceType], 298 &This->dirty_rect[FaceType], 299 This->base.base.info.width0, 300 This->base.base.info.height0); 301 } 302 return D3D_OK; 303} 304 305IDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = { 306 (void *)NineUnknown_QueryInterface, 307 (void *)NineUnknown_AddRef, 308 (void *)NineUnknown_Release, 309 (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ 310 (void *)NineUnknown_SetPrivateData, 311 (void *)NineUnknown_GetPrivateData, 312 (void *)NineUnknown_FreePrivateData, 313 (void *)NineResource9_SetPriority, 314 (void *)NineResource9_GetPriority, 315 (void *)NineBaseTexture9_PreLoad, 316 (void *)NineResource9_GetType, 317 (void *)NineBaseTexture9_SetLOD, 318 (void *)NineBaseTexture9_GetLOD, 319 (void *)NineBaseTexture9_GetLevelCount, 320 (void *)NineBaseTexture9_SetAutoGenFilterType, 321 (void *)NineBaseTexture9_GetAutoGenFilterType, 322 (void *)NineBaseTexture9_GenerateMipSubLevels, 323 (void *)NineCubeTexture9_GetLevelDesc, 324 (void *)NineCubeTexture9_GetCubeMapSurface, 325 (void *)NineCubeTexture9_LockRect, 326 (void *)NineCubeTexture9_UnlockRect, 327 (void *)NineCubeTexture9_AddDirtyRect 328}; 329 330static const GUID *NineCubeTexture9_IIDs[] = { 331 &IID_IDirect3DCubeTexture9, 332 &IID_IDirect3DBaseTexture9, 333 &IID_IDirect3DResource9, 334 &IID_IUnknown, 335 NULL 336}; 337 338HRESULT 339NineCubeTexture9_new( struct NineDevice9 *pDevice, 340 UINT EdgeLength, UINT Levels, 341 DWORD Usage, 342 D3DFORMAT Format, 343 D3DPOOL Pool, 344 struct NineCubeTexture9 **ppOut, 345 HANDLE *pSharedHandle ) 346{ 347 NINE_DEVICE_CHILD_NEW(CubeTexture9, ppOut, pDevice, 348 EdgeLength, Levels, 349 Usage, Format, Pool, pSharedHandle); 350} 351