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_memory_helper.h" 28#include "nine_helpers.h" 29#include "nine_pipe.h" 30 31#define DBG_CHANNEL DBG_CUBETEXTURE 32 33 34static HRESULT 35NineCubeTexture9_ctor( struct NineCubeTexture9 *This, 36 struct NineUnknownParams *pParams, 37 UINT EdgeLength, UINT Levels, 38 DWORD Usage, 39 D3DFORMAT Format, 40 D3DPOOL Pool, 41 HANDLE *pSharedHandle ) 42{ 43 struct pipe_resource *info = &This->base.base.info; 44 struct pipe_screen *screen = pParams->device->screen; 45 enum pipe_format pf; 46 unsigned i, l, f, offset, face_size = 0; 47 unsigned *level_offsets = NULL; 48 D3DSURFACE_DESC sfdesc; 49 struct nine_allocation *p; 50 HRESULT hr; 51 52 DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d " 53 "Format=%d Pool=%d pSharedHandle=%p\n", 54 This, pParams, EdgeLength, Levels, Usage, 55 Format, Pool, pSharedHandle); 56 57 This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */ 58 59 user_assert(EdgeLength, D3DERR_INVALIDCALL); 60 61 /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */ 62 user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ 63 64 user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || 65 (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); 66 67 if (Usage & D3DUSAGE_AUTOGENMIPMAP) 68 Levels = 0; 69 70 pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_CUBE, 0, 71 PIPE_BIND_SAMPLER_VIEW, FALSE, 72 Pool == D3DPOOL_SCRATCH); 73 74 if (pf == PIPE_FORMAT_NONE) 75 return D3DERR_INVALIDCALL; 76 77 if (compressed_format(Format)) { 78 const unsigned w = util_format_get_blockwidth(pf); 79 const unsigned h = util_format_get_blockheight(pf); 80 81 user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL); 82 } 83 84 info->screen = pParams->device->screen; 85 info->target = PIPE_TEXTURE_CUBE; 86 info->format = pf; 87 info->width0 = EdgeLength; 88 info->height0 = EdgeLength; 89 info->depth0 = 1; 90 if (Levels) 91 info->last_level = Levels - 1; 92 else 93 info->last_level = util_logbase2(EdgeLength); 94 info->array_size = 6; 95 info->nr_samples = 0; 96 info->nr_storage_samples = 0; 97 info->bind = PIPE_BIND_SAMPLER_VIEW; 98 info->usage = PIPE_USAGE_DEFAULT; 99 info->flags = 0; 100 101 if (Usage & D3DUSAGE_RENDERTARGET) 102 info->bind |= PIPE_BIND_RENDER_TARGET; 103 if (Usage & D3DUSAGE_DEPTHSTENCIL) 104 info->bind |= PIPE_BIND_DEPTH_STENCIL; 105 106 if (Usage & D3DUSAGE_DYNAMIC) { 107 info->usage = PIPE_USAGE_DYNAMIC; 108 } 109 if (Usage & D3DUSAGE_SOFTWAREPROCESSING) 110 DBG("Application asked for Software Vertex Processing, " 111 "but this is unimplemented\n"); 112 113 hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_CUBETEXTURE, 114 Format, Pool, Usage); 115 if (FAILED(hr)) 116 return hr; 117 This->base.pstype = 2; 118 119 if (Pool != D3DPOOL_DEFAULT) { 120 level_offsets = alloca(sizeof(unsigned) * This->base.level_count); 121 face_size = nine_format_get_size_and_offsets(pf, level_offsets, 122 EdgeLength, EdgeLength, 123 This->base.level_count-1); 124 This->managed_buffer = nine_allocate(pParams->device->allocator, 6 * face_size); 125 if (!This->managed_buffer) 126 return E_OUTOFMEMORY; 127 } 128 129 This->surfaces = CALLOC(6 * This->base.level_count, sizeof(*This->surfaces)); 130 if (!This->surfaces) 131 return E_OUTOFMEMORY; 132 133 /* Create all the surfaces right away. 134 * They manage backing storage, and transfers (LockRect) are deferred 135 * to them. 136 */ 137 sfdesc.Format = Format; 138 sfdesc.Type = D3DRTYPE_SURFACE; 139 sfdesc.Usage = Usage; 140 sfdesc.Pool = Pool; 141 sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; 142 sfdesc.MultiSampleQuality = 0; 143 /* We allocate the memory for the surfaces as continous blocks. 144 * This is the expected behaviour, however we haven't tested for 145 * cube textures in which order the faces/levels should be in memory 146 */ 147 for (f = 0; f < 6; f++) { 148 offset = f * face_size; 149 for (l = 0; l < This->base.level_count; l++) { 150 sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l); 151 p = This->managed_buffer ? 152 nine_suballocate(pParams->device->allocator, This->managed_buffer, offset + level_offsets[l]) : NULL; 153 154 hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), 155 This->base.base.resource, p, D3DRTYPE_CUBETEXTURE, 156 l, f, &sfdesc, &This->surfaces[f + 6 * l]); 157 if (FAILED(hr)) 158 return hr; 159 } 160 } 161 162 for (i = 0; i < 6; ++i) { 163 /* Textures start initially dirty */ 164 This->dirty_rect[i].width = EdgeLength; 165 This->dirty_rect[i].height = EdgeLength; 166 This->dirty_rect[i].depth = 1; 167 } 168 169 return D3D_OK; 170} 171 172static void 173NineCubeTexture9_dtor( struct NineCubeTexture9 *This ) 174{ 175 unsigned i; 176 bool is_worker = nine_context_is_worker(This->base.base.base.device); 177 178 DBG("This=%p\n", This); 179 180 if (This->surfaces) { 181 for (i = 0; i < This->base.level_count * 6; ++i) 182 if (This->surfaces[i]) 183 NineUnknown_Destroy(&This->surfaces[i]->base.base); 184 FREE(This->surfaces); 185 } 186 187 if (This->managed_buffer) { 188 if (is_worker) 189 nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer); 190 else 191 nine_free(This->base.base.base.device->allocator, This->managed_buffer); 192 } 193 194 NineBaseTexture9_dtor(&This->base); 195} 196 197HRESULT NINE_WINAPI 198NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, 199 UINT Level, 200 D3DSURFACE_DESC *pDesc ) 201{ 202 DBG("This=%p Level=%u pDesc=%p\n", This, Level, pDesc); 203 204 user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); 205 206 *pDesc = This->surfaces[Level * 6]->desc; 207 208 return D3D_OK; 209} 210 211HRESULT NINE_WINAPI 212NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, 213 D3DCUBEMAP_FACES FaceType, 214 UINT Level, 215 IDirect3DSurface9 **ppCubeMapSurface ) 216{ 217 const unsigned s = Level * 6 + FaceType; 218 219 DBG("This=%p FaceType=%d Level=%u ppCubeMapSurface=%p\n", 220 This, FaceType, Level, ppCubeMapSurface); 221 222 user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); 223 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 224 225 NineUnknown_AddRef(NineUnknown(This->surfaces[s])); 226 *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s]; 227 228 return D3D_OK; 229} 230 231HRESULT NINE_WINAPI 232NineCubeTexture9_LockRect( struct NineCubeTexture9 *This, 233 D3DCUBEMAP_FACES FaceType, 234 UINT Level, 235 D3DLOCKED_RECT *pLockedRect, 236 const RECT *pRect, 237 DWORD Flags ) 238{ 239 const unsigned s = Level * 6 + FaceType; 240 241 DBG("This=%p FaceType=%d Level=%u pLockedRect=%p pRect=%p Flags=%d\n", 242 This, FaceType, Level, pLockedRect, pRect, Flags); 243 244 user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); 245 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 246 247 return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags); 248} 249 250HRESULT NINE_WINAPI 251NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, 252 D3DCUBEMAP_FACES FaceType, 253 UINT Level ) 254{ 255 const unsigned s = Level * 6 + FaceType; 256 257 DBG("This=%p FaceType=%d Level=%u\n", This, FaceType, Level); 258 259 user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL); 260 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 261 262 return NineSurface9_UnlockRect(This->surfaces[s]); 263} 264 265HRESULT NINE_WINAPI 266NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, 267 D3DCUBEMAP_FACES FaceType, 268 const RECT *pDirtyRect ) 269{ 270 DBG("This=%p FaceType=%d pDirtyRect=%p\n", This, FaceType, pDirtyRect); 271 272 user_assert(FaceType < 6, D3DERR_INVALIDCALL); 273 274 if (This->base.base.pool != D3DPOOL_MANAGED) { 275 if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { 276 This->base.dirty_mip = TRUE; 277 BASETEX_REGISTER_UPDATE(&This->base); 278 } 279 return D3D_OK; 280 } 281 282 if (This->base.base.pool == D3DPOOL_MANAGED) { 283 This->base.managed.dirty = TRUE; 284 BASETEX_REGISTER_UPDATE(&This->base); 285 } 286 287 if (!pDirtyRect) { 288 u_box_origin_2d(This->base.base.info.width0, 289 This->base.base.info.height0, 290 &This->dirty_rect[FaceType]); 291 } else { 292 if (This->dirty_rect[FaceType].width == 0) { 293 rect_to_pipe_box_clamp(&This->dirty_rect[FaceType], pDirtyRect); 294 } else { 295 struct pipe_box box; 296 rect_to_pipe_box_clamp(&box, pDirtyRect); 297 u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType], 298 &box); 299 } 300 (void) u_box_clip_2d(&This->dirty_rect[FaceType], 301 &This->dirty_rect[FaceType], 302 This->base.base.info.width0, 303 This->base.base.info.height0); 304 } 305 return D3D_OK; 306} 307 308IDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = { 309 (void *)NineUnknown_QueryInterface, 310 (void *)NineUnknown_AddRef, 311 (void *)NineUnknown_Release, 312 (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ 313 (void *)NineUnknown_SetPrivateData, 314 (void *)NineUnknown_GetPrivateData, 315 (void *)NineUnknown_FreePrivateData, 316 (void *)NineResource9_SetPriority, 317 (void *)NineResource9_GetPriority, 318 (void *)NineBaseTexture9_PreLoad, 319 (void *)NineResource9_GetType, 320 (void *)NineBaseTexture9_SetLOD, 321 (void *)NineBaseTexture9_GetLOD, 322 (void *)NineBaseTexture9_GetLevelCount, 323 (void *)NineBaseTexture9_SetAutoGenFilterType, 324 (void *)NineBaseTexture9_GetAutoGenFilterType, 325 (void *)NineBaseTexture9_GenerateMipSubLevels, 326 (void *)NineCubeTexture9_GetLevelDesc, 327 (void *)NineCubeTexture9_GetCubeMapSurface, 328 (void *)NineCubeTexture9_LockRect, 329 (void *)NineCubeTexture9_UnlockRect, 330 (void *)NineCubeTexture9_AddDirtyRect 331}; 332 333static const GUID *NineCubeTexture9_IIDs[] = { 334 &IID_IDirect3DCubeTexture9, 335 &IID_IDirect3DBaseTexture9, 336 &IID_IDirect3DResource9, 337 &IID_IUnknown, 338 NULL 339}; 340 341HRESULT 342NineCubeTexture9_new( struct NineDevice9 *pDevice, 343 UINT EdgeLength, UINT Levels, 344 DWORD Usage, 345 D3DFORMAT Format, 346 D3DPOOL Pool, 347 struct NineCubeTexture9 **ppOut, 348 HANDLE *pSharedHandle ) 349{ 350 NINE_DEVICE_CHILD_NEW(CubeTexture9, ppOut, pDevice, 351 EdgeLength, Levels, 352 Usage, Format, Pool, pSharedHandle); 353} 354