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