1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22b8e80941Smrg 23b8e80941Smrg#include "c99_alloca.h" 24b8e80941Smrg 25b8e80941Smrg#include "device9.h" 26b8e80941Smrg#include "surface9.h" 27b8e80941Smrg#include "texture9.h" 28b8e80941Smrg#include "nine_helpers.h" 29b8e80941Smrg#include "nine_pipe.h" 30b8e80941Smrg#include "nine_dump.h" 31b8e80941Smrg 32b8e80941Smrg#include "pipe/p_state.h" 33b8e80941Smrg#include "pipe/p_context.h" 34b8e80941Smrg#include "pipe/p_screen.h" 35b8e80941Smrg#include "util/u_inlines.h" 36b8e80941Smrg#include "util/u_resource.h" 37b8e80941Smrg 38b8e80941Smrg#define DBG_CHANNEL DBG_TEXTURE 39b8e80941Smrg 40b8e80941Smrgstatic HRESULT 41b8e80941SmrgNineTexture9_ctor( struct NineTexture9 *This, 42b8e80941Smrg struct NineUnknownParams *pParams, 43b8e80941Smrg UINT Width, UINT Height, UINT Levels, 44b8e80941Smrg DWORD Usage, 45b8e80941Smrg D3DFORMAT Format, 46b8e80941Smrg D3DPOOL Pool, 47b8e80941Smrg HANDLE *pSharedHandle ) 48b8e80941Smrg{ 49b8e80941Smrg struct pipe_screen *screen = pParams->device->screen; 50b8e80941Smrg struct pipe_resource *info = &This->base.base.info; 51b8e80941Smrg enum pipe_format pf; 52b8e80941Smrg unsigned *level_offsets; 53b8e80941Smrg unsigned l; 54b8e80941Smrg D3DSURFACE_DESC sfdesc; 55b8e80941Smrg HRESULT hr; 56b8e80941Smrg void *user_buffer = NULL, *user_buffer_for_level; 57b8e80941Smrg 58b8e80941Smrg DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s " 59b8e80941Smrg "pSharedHandle=%p\n", This, Width, Height, Levels, 60b8e80941Smrg nine_D3DUSAGE_to_str(Usage), 61b8e80941Smrg d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle); 62b8e80941Smrg 63b8e80941Smrg user_assert(Width && Height, D3DERR_INVALIDCALL); 64b8e80941Smrg 65b8e80941Smrg /* pSharedHandle: can be non-null for ex only. 66b8e80941Smrg * D3DPOOL_SYSTEMMEM: Levels must be 1 67b8e80941Smrg * D3DPOOL_DEFAULT: no restriction for Levels 68b8e80941Smrg * Other Pools are forbidden. */ 69b8e80941Smrg user_assert(!pSharedHandle || pParams->device->ex, D3DERR_INVALIDCALL); 70b8e80941Smrg user_assert(!pSharedHandle || 71b8e80941Smrg (Pool == D3DPOOL_SYSTEMMEM && Levels == 1) || 72b8e80941Smrg Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); 73b8e80941Smrg 74b8e80941Smrg user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || 75b8e80941Smrg (Pool != D3DPOOL_SYSTEMMEM && Pool != D3DPOOL_SCRATCH && Levels <= 1), 76b8e80941Smrg D3DERR_INVALIDCALL); 77b8e80941Smrg 78b8e80941Smrg /* TODO: implement pSharedHandle for D3DPOOL_DEFAULT (cross process 79b8e80941Smrg * buffer sharing). 80b8e80941Smrg * 81b8e80941Smrg * Gem names may have fit but they're depreciated and won't work on render-nodes. 82b8e80941Smrg * One solution is to use shm buffers. We would use a /dev/shm file, fill the first 83b8e80941Smrg * values to tell it is a nine buffer, the size, which function created it, etc, 84b8e80941Smrg * and then it would contain the data. The handle would be a number, corresponding to 85b8e80941Smrg * the file to read (/dev/shm/nine-share-4 for example would be 4). 86b8e80941Smrg * 87b8e80941Smrg * Wine just ignores the argument, which works only if the app creates the handle 88b8e80941Smrg * and won't use it. Instead of failing, we support that situation by putting an 89b8e80941Smrg * invalid handle, that we would fail to import. Please note that we don't advertise 90b8e80941Smrg * the flag indicating the support for that feature, but apps seem to not care. 91b8e80941Smrg */ 92b8e80941Smrg 93b8e80941Smrg if (pSharedHandle && Pool == D3DPOOL_DEFAULT) { 94b8e80941Smrg if (!*pSharedHandle) { 95b8e80941Smrg DBG("Creating Texture with invalid handle. Importing will fail\n."); 96b8e80941Smrg *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */ 97b8e80941Smrg pSharedHandle = NULL; 98b8e80941Smrg } else { 99b8e80941Smrg ERR("Application tries to use cross-process sharing feature. Nine " 100b8e80941Smrg "doesn't support it"); 101b8e80941Smrg return D3DERR_INVALIDCALL; 102b8e80941Smrg } 103b8e80941Smrg } 104b8e80941Smrg 105b8e80941Smrg if (Usage & D3DUSAGE_AUTOGENMIPMAP) 106b8e80941Smrg Levels = 0; 107b8e80941Smrg 108b8e80941Smrg pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0, 109b8e80941Smrg PIPE_BIND_SAMPLER_VIEW, FALSE, 110b8e80941Smrg Pool == D3DPOOL_SCRATCH); 111b8e80941Smrg 112b8e80941Smrg if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE) 113b8e80941Smrg return D3DERR_INVALIDCALL; 114b8e80941Smrg 115b8e80941Smrg if (compressed_format(Format)) { 116b8e80941Smrg const unsigned w = util_format_get_blockwidth(pf); 117b8e80941Smrg const unsigned h = util_format_get_blockheight(pf); 118b8e80941Smrg 119b8e80941Smrg user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); 120b8e80941Smrg } 121b8e80941Smrg 122b8e80941Smrg info->screen = screen; 123b8e80941Smrg info->target = PIPE_TEXTURE_2D; 124b8e80941Smrg info->format = pf; 125b8e80941Smrg info->width0 = Width; 126b8e80941Smrg info->height0 = Height; 127b8e80941Smrg info->depth0 = 1; 128b8e80941Smrg if (Levels) 129b8e80941Smrg info->last_level = Levels - 1; 130b8e80941Smrg else 131b8e80941Smrg info->last_level = util_logbase2(MAX2(Width, Height)); 132b8e80941Smrg info->array_size = 1; 133b8e80941Smrg info->nr_samples = 0; 134b8e80941Smrg info->nr_storage_samples = 0; 135b8e80941Smrg info->bind = PIPE_BIND_SAMPLER_VIEW; 136b8e80941Smrg info->usage = PIPE_USAGE_DEFAULT; 137b8e80941Smrg info->flags = 0; 138b8e80941Smrg 139b8e80941Smrg if (Usage & D3DUSAGE_RENDERTARGET) 140b8e80941Smrg info->bind |= PIPE_BIND_RENDER_TARGET; 141b8e80941Smrg if (Usage & D3DUSAGE_DEPTHSTENCIL) 142b8e80941Smrg info->bind |= PIPE_BIND_DEPTH_STENCIL; 143b8e80941Smrg 144b8e80941Smrg if (Usage & D3DUSAGE_DYNAMIC) { 145b8e80941Smrg info->usage = PIPE_USAGE_DYNAMIC; 146b8e80941Smrg } 147b8e80941Smrg 148b8e80941Smrg if (Usage & D3DUSAGE_SOFTWAREPROCESSING) 149b8e80941Smrg DBG("Application asked for Software Vertex Processing, " 150b8e80941Smrg "but this is unimplemented\n"); 151b8e80941Smrg 152b8e80941Smrg if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */ 153b8e80941Smrg user_buffer = (void *)*pSharedHandle; 154b8e80941Smrg level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); 155b8e80941Smrg (void) nine_format_get_size_and_offsets(pf, level_offsets, 156b8e80941Smrg Width, Height, 157b8e80941Smrg info->last_level); 158b8e80941Smrg } else if (Pool != D3DPOOL_DEFAULT) { 159b8e80941Smrg /* TODO: For D3DUSAGE_AUTOGENMIPMAP, it is likely we only have to 160b8e80941Smrg * allocate only for the first level, since it is the only lockable 161b8e80941Smrg * level. Check apps don't crash if we allocate smaller buffer (some 162b8e80941Smrg * apps access sublevels of texture even if they locked only first 163b8e80941Smrg * level) */ 164b8e80941Smrg level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); 165b8e80941Smrg user_buffer = align_calloc( 166b8e80941Smrg nine_format_get_size_and_offsets(pf, level_offsets, 167b8e80941Smrg Width, Height, 168b8e80941Smrg info->last_level), 32); 169b8e80941Smrg This->managed_buffer = user_buffer; 170b8e80941Smrg if (!This->managed_buffer) 171b8e80941Smrg return E_OUTOFMEMORY; 172b8e80941Smrg } 173b8e80941Smrg 174b8e80941Smrg This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces)); 175b8e80941Smrg if (!This->surfaces) 176b8e80941Smrg return E_OUTOFMEMORY; 177b8e80941Smrg 178b8e80941Smrg hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage); 179b8e80941Smrg if (FAILED(hr)) 180b8e80941Smrg return hr; 181b8e80941Smrg This->base.pstype = (Height == 1) ? 1 : 0; 182b8e80941Smrg 183b8e80941Smrg /* Create all the surfaces right away. 184b8e80941Smrg * They manage backing storage, and transfers (LockRect) are deferred 185b8e80941Smrg * to them. 186b8e80941Smrg */ 187b8e80941Smrg sfdesc.Format = Format; 188b8e80941Smrg sfdesc.Type = D3DRTYPE_SURFACE; 189b8e80941Smrg sfdesc.Usage = Usage; 190b8e80941Smrg sfdesc.Pool = Pool; 191b8e80941Smrg sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; 192b8e80941Smrg sfdesc.MultiSampleQuality = 0; 193b8e80941Smrg 194b8e80941Smrg for (l = 0; l <= info->last_level; ++l) { 195b8e80941Smrg sfdesc.Width = u_minify(Width, l); 196b8e80941Smrg sfdesc.Height = u_minify(Height, l); 197b8e80941Smrg /* Some apps expect the memory to be allocated in 198b8e80941Smrg * continous blocks */ 199b8e80941Smrg user_buffer_for_level = user_buffer ? user_buffer + 200b8e80941Smrg level_offsets[l] : NULL; 201b8e80941Smrg 202b8e80941Smrg hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), 203b8e80941Smrg This->base.base.resource, user_buffer_for_level, 204b8e80941Smrg D3DRTYPE_TEXTURE, l, 0, 205b8e80941Smrg &sfdesc, &This->surfaces[l]); 206b8e80941Smrg if (FAILED(hr)) 207b8e80941Smrg return hr; 208b8e80941Smrg } 209b8e80941Smrg 210b8e80941Smrg /* Textures start initially dirty */ 211b8e80941Smrg This->dirty_rect.width = Width; 212b8e80941Smrg This->dirty_rect.height = Height; 213b8e80941Smrg This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */ 214b8e80941Smrg 215b8e80941Smrg if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */ 216b8e80941Smrg *pSharedHandle = This->surfaces[0]->data; 217b8e80941Smrg } 218b8e80941Smrg 219b8e80941Smrg return D3D_OK; 220b8e80941Smrg} 221b8e80941Smrg 222b8e80941Smrgstatic void 223b8e80941SmrgNineTexture9_dtor( struct NineTexture9 *This ) 224b8e80941Smrg{ 225b8e80941Smrg unsigned l; 226b8e80941Smrg 227b8e80941Smrg DBG("This=%p\n", This); 228b8e80941Smrg 229b8e80941Smrg if (This->surfaces) { 230b8e80941Smrg /* The surfaces should have 0 references and be unbound now. */ 231b8e80941Smrg for (l = 0; l <= This->base.base.info.last_level; ++l) 232b8e80941Smrg if (This->surfaces[l]) 233b8e80941Smrg NineUnknown_Destroy(&This->surfaces[l]->base.base); 234b8e80941Smrg FREE(This->surfaces); 235b8e80941Smrg } 236b8e80941Smrg 237b8e80941Smrg if (This->managed_buffer) 238b8e80941Smrg align_free(This->managed_buffer); 239b8e80941Smrg 240b8e80941Smrg NineBaseTexture9_dtor(&This->base); 241b8e80941Smrg} 242b8e80941Smrg 243b8e80941SmrgHRESULT NINE_WINAPI 244b8e80941SmrgNineTexture9_GetLevelDesc( struct NineTexture9 *This, 245b8e80941Smrg UINT Level, 246b8e80941Smrg D3DSURFACE_DESC *pDesc ) 247b8e80941Smrg{ 248b8e80941Smrg DBG("This=%p Level=%d pDesc=%p\n", This, Level, pDesc); 249b8e80941Smrg 250b8e80941Smrg user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 251b8e80941Smrg user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 252b8e80941Smrg D3DERR_INVALIDCALL); 253b8e80941Smrg 254b8e80941Smrg *pDesc = This->surfaces[Level]->desc; 255b8e80941Smrg 256b8e80941Smrg return D3D_OK; 257b8e80941Smrg} 258b8e80941Smrg 259b8e80941SmrgHRESULT NINE_WINAPI 260b8e80941SmrgNineTexture9_GetSurfaceLevel( struct NineTexture9 *This, 261b8e80941Smrg UINT Level, 262b8e80941Smrg IDirect3DSurface9 **ppSurfaceLevel ) 263b8e80941Smrg{ 264b8e80941Smrg DBG("This=%p Level=%d ppSurfaceLevel=%p\n", This, Level, ppSurfaceLevel); 265b8e80941Smrg 266b8e80941Smrg user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 267b8e80941Smrg user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 268b8e80941Smrg D3DERR_INVALIDCALL); 269b8e80941Smrg 270b8e80941Smrg NineUnknown_AddRef(NineUnknown(This->surfaces[Level])); 271b8e80941Smrg *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level]; 272b8e80941Smrg 273b8e80941Smrg return D3D_OK; 274b8e80941Smrg} 275b8e80941Smrg 276b8e80941SmrgHRESULT NINE_WINAPI 277b8e80941SmrgNineTexture9_LockRect( struct NineTexture9 *This, 278b8e80941Smrg UINT Level, 279b8e80941Smrg D3DLOCKED_RECT *pLockedRect, 280b8e80941Smrg const RECT *pRect, 281b8e80941Smrg DWORD Flags ) 282b8e80941Smrg{ 283b8e80941Smrg DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n", 284b8e80941Smrg This, Level, pLockedRect, pRect, Flags); 285b8e80941Smrg 286b8e80941Smrg user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 287b8e80941Smrg user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), 288b8e80941Smrg D3DERR_INVALIDCALL); 289b8e80941Smrg 290b8e80941Smrg return NineSurface9_LockRect(This->surfaces[Level], pLockedRect, 291b8e80941Smrg pRect, Flags); 292b8e80941Smrg} 293b8e80941Smrg 294b8e80941SmrgHRESULT NINE_WINAPI 295b8e80941SmrgNineTexture9_UnlockRect( struct NineTexture9 *This, 296b8e80941Smrg UINT Level ) 297b8e80941Smrg{ 298b8e80941Smrg DBG("This=%p Level=%u\n", This, Level); 299b8e80941Smrg 300b8e80941Smrg user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); 301b8e80941Smrg 302b8e80941Smrg return NineSurface9_UnlockRect(This->surfaces[Level]); 303b8e80941Smrg} 304b8e80941Smrg 305b8e80941SmrgHRESULT NINE_WINAPI 306b8e80941SmrgNineTexture9_AddDirtyRect( struct NineTexture9 *This, 307b8e80941Smrg const RECT *pDirtyRect ) 308b8e80941Smrg{ 309b8e80941Smrg DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect, 310b8e80941Smrg pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0, 311b8e80941Smrg pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0); 312b8e80941Smrg 313b8e80941Smrg /* Tracking dirty regions on DEFAULT resources is pointless, 314b8e80941Smrg * because we always write to the final storage. Just marked it dirty in 315b8e80941Smrg * case we need to generate mip maps. 316b8e80941Smrg */ 317b8e80941Smrg if (This->base.base.pool == D3DPOOL_DEFAULT) { 318b8e80941Smrg if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { 319b8e80941Smrg This->base.dirty_mip = TRUE; 320b8e80941Smrg BASETEX_REGISTER_UPDATE(&This->base); 321b8e80941Smrg } 322b8e80941Smrg return D3D_OK; 323b8e80941Smrg } 324b8e80941Smrg 325b8e80941Smrg if (This->base.base.pool == D3DPOOL_MANAGED) { 326b8e80941Smrg This->base.managed.dirty = TRUE; 327b8e80941Smrg BASETEX_REGISTER_UPDATE(&This->base); 328b8e80941Smrg } 329b8e80941Smrg 330b8e80941Smrg if (!pDirtyRect) { 331b8e80941Smrg u_box_origin_2d(This->base.base.info.width0, 332b8e80941Smrg This->base.base.info.height0, &This->dirty_rect); 333b8e80941Smrg } else { 334b8e80941Smrg if (This->dirty_rect.width == 0) { 335b8e80941Smrg rect_to_pipe_box_clamp(&This->dirty_rect, pDirtyRect); 336b8e80941Smrg } else { 337b8e80941Smrg struct pipe_box box; 338b8e80941Smrg rect_to_pipe_box_clamp(&box, pDirtyRect); 339b8e80941Smrg u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box); 340b8e80941Smrg } 341b8e80941Smrg (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect, 342b8e80941Smrg This->base.base.info.width0, 343b8e80941Smrg This->base.base.info.height0); 344b8e80941Smrg } 345b8e80941Smrg return D3D_OK; 346b8e80941Smrg} 347b8e80941Smrg 348b8e80941SmrgIDirect3DTexture9Vtbl NineTexture9_vtable = { 349b8e80941Smrg (void *)NineUnknown_QueryInterface, 350b8e80941Smrg (void *)NineUnknown_AddRef, 351b8e80941Smrg (void *)NineUnknown_Release, 352b8e80941Smrg (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ 353b8e80941Smrg (void *)NineUnknown_SetPrivateData, 354b8e80941Smrg (void *)NineUnknown_GetPrivateData, 355b8e80941Smrg (void *)NineUnknown_FreePrivateData, 356b8e80941Smrg (void *)NineResource9_SetPriority, 357b8e80941Smrg (void *)NineResource9_GetPriority, 358b8e80941Smrg (void *)NineBaseTexture9_PreLoad, 359b8e80941Smrg (void *)NineResource9_GetType, 360b8e80941Smrg (void *)NineBaseTexture9_SetLOD, 361b8e80941Smrg (void *)NineBaseTexture9_GetLOD, 362b8e80941Smrg (void *)NineBaseTexture9_GetLevelCount, 363b8e80941Smrg (void *)NineBaseTexture9_SetAutoGenFilterType, 364b8e80941Smrg (void *)NineBaseTexture9_GetAutoGenFilterType, 365b8e80941Smrg (void *)NineBaseTexture9_GenerateMipSubLevels, 366b8e80941Smrg (void *)NineTexture9_GetLevelDesc, 367b8e80941Smrg (void *)NineTexture9_GetSurfaceLevel, 368b8e80941Smrg (void *)NineTexture9_LockRect, 369b8e80941Smrg (void *)NineTexture9_UnlockRect, 370b8e80941Smrg (void *)NineTexture9_AddDirtyRect 371b8e80941Smrg}; 372b8e80941Smrg 373b8e80941Smrgstatic const GUID *NineTexture9_IIDs[] = { 374b8e80941Smrg &IID_IDirect3DTexture9, 375b8e80941Smrg &IID_IDirect3DBaseTexture9, 376b8e80941Smrg &IID_IDirect3DResource9, 377b8e80941Smrg &IID_IUnknown, 378b8e80941Smrg NULL 379b8e80941Smrg}; 380b8e80941Smrg 381b8e80941SmrgHRESULT 382b8e80941SmrgNineTexture9_new( struct NineDevice9 *pDevice, 383b8e80941Smrg UINT Width, UINT Height, UINT Levels, 384b8e80941Smrg DWORD Usage, 385b8e80941Smrg D3DFORMAT Format, 386b8e80941Smrg D3DPOOL Pool, 387b8e80941Smrg struct NineTexture9 **ppOut, 388b8e80941Smrg HANDLE *pSharedHandle ) 389b8e80941Smrg{ 390b8e80941Smrg NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice, 391b8e80941Smrg Width, Height, Levels, 392b8e80941Smrg Usage, Format, Pool, pSharedHandle); 393b8e80941Smrg} 394