17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
87ec681f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom
97ec681f3Smrg * the Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
197ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
207ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
217ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */
227ec681f3Smrg
237ec681f3Smrg#include "c99_alloca.h"
247ec681f3Smrg
257ec681f3Smrg#include "device9.h"
267ec681f3Smrg#include "surface9.h"
277ec681f3Smrg#include "texture9.h"
287ec681f3Smrg#include "nine_helpers.h"
297ec681f3Smrg#include "nine_memory_helper.h"
307ec681f3Smrg#include "nine_pipe.h"
317ec681f3Smrg#include "nine_dump.h"
327ec681f3Smrg
337ec681f3Smrg#include "pipe/p_state.h"
347ec681f3Smrg#include "pipe/p_context.h"
357ec681f3Smrg#include "pipe/p_screen.h"
367ec681f3Smrg#include "util/u_inlines.h"
377ec681f3Smrg#include "util/u_resource.h"
387ec681f3Smrg
397ec681f3Smrg#define DBG_CHANNEL DBG_TEXTURE
407ec681f3Smrg
417ec681f3Smrgstatic HRESULT
427ec681f3SmrgNineTexture9_ctor( struct NineTexture9 *This,
437ec681f3Smrg                   struct NineUnknownParams *pParams,
447ec681f3Smrg                   UINT Width, UINT Height, UINT Levels,
457ec681f3Smrg                   DWORD Usage,
467ec681f3Smrg                   D3DFORMAT Format,
477ec681f3Smrg                   D3DPOOL Pool,
487ec681f3Smrg                   HANDLE *pSharedHandle )
497ec681f3Smrg{
507ec681f3Smrg    struct pipe_screen *screen = pParams->device->screen;
517ec681f3Smrg    struct pipe_resource *info = &This->base.base.info;
527ec681f3Smrg    enum pipe_format pf;
537ec681f3Smrg    unsigned *level_offsets = NULL;
547ec681f3Smrg    unsigned l;
557ec681f3Smrg    D3DSURFACE_DESC sfdesc;
567ec681f3Smrg    HRESULT hr;
577ec681f3Smrg    struct nine_allocation *user_buffer = NULL, *user_buffer_for_level;
587ec681f3Smrg
597ec681f3Smrg    This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */
607ec681f3Smrg
617ec681f3Smrg    DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
627ec681f3Smrg        "pSharedHandle=%p\n", This, Width, Height, Levels,
637ec681f3Smrg        nine_D3DUSAGE_to_str(Usage),
647ec681f3Smrg        d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle);
657ec681f3Smrg
667ec681f3Smrg    user_assert(Width && Height, D3DERR_INVALIDCALL);
677ec681f3Smrg
687ec681f3Smrg    /* pSharedHandle: can be non-null for ex only.
697ec681f3Smrg     * D3DPOOL_SYSTEMMEM: Levels must be 1
707ec681f3Smrg     * D3DPOOL_DEFAULT: no restriction for Levels
717ec681f3Smrg     * Other Pools are forbidden. */
727ec681f3Smrg    user_assert(!pSharedHandle || pParams->device->ex, D3DERR_INVALIDCALL);
737ec681f3Smrg    user_assert(!pSharedHandle ||
747ec681f3Smrg                (Pool == D3DPOOL_SYSTEMMEM && Levels == 1) ||
757ec681f3Smrg                Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
767ec681f3Smrg
777ec681f3Smrg    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
787ec681f3Smrg                (Pool != D3DPOOL_SYSTEMMEM && Pool != D3DPOOL_SCRATCH && Levels <= 1),
797ec681f3Smrg                D3DERR_INVALIDCALL);
807ec681f3Smrg
817ec681f3Smrg    /* TODO: implement pSharedHandle for D3DPOOL_DEFAULT (cross process
827ec681f3Smrg     * buffer sharing).
837ec681f3Smrg     *
847ec681f3Smrg     * Gem names may have fit but they're depreciated and won't work on render-nodes.
857ec681f3Smrg     * One solution is to use shm buffers. We would use a /dev/shm file, fill the first
867ec681f3Smrg     * values to tell it is a nine buffer, the size, which function created it, etc,
877ec681f3Smrg     * and then it would contain the data. The handle would be a number, corresponding to
887ec681f3Smrg     * the file to read (/dev/shm/nine-share-4 for example would be 4).
897ec681f3Smrg     *
907ec681f3Smrg     * Wine just ignores the argument, which works only if the app creates the handle
917ec681f3Smrg     * and won't use it. Instead of failing, we support that situation by putting an
927ec681f3Smrg     * invalid handle, that we would fail to import. Please note that we don't advertise
937ec681f3Smrg     * the flag indicating the support for that feature, but apps seem to not care.
947ec681f3Smrg     */
957ec681f3Smrg
967ec681f3Smrg    if (pSharedHandle && Pool == D3DPOOL_DEFAULT) {
977ec681f3Smrg        if (!*pSharedHandle) {
987ec681f3Smrg            DBG("Creating Texture with invalid handle. Importing will fail\n.");
997ec681f3Smrg            *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */
1007ec681f3Smrg            pSharedHandle = NULL;
1017ec681f3Smrg        } else {
1027ec681f3Smrg            ERR("Application tries to use cross-process sharing feature. Nine "
1037ec681f3Smrg                "doesn't support it");
1047ec681f3Smrg            return D3DERR_INVALIDCALL;
1057ec681f3Smrg        }
1067ec681f3Smrg    }
1077ec681f3Smrg
1087ec681f3Smrg    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
1097ec681f3Smrg        Levels = 0;
1107ec681f3Smrg
1117ec681f3Smrg    pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0,
1127ec681f3Smrg                                     PIPE_BIND_SAMPLER_VIEW, FALSE,
1137ec681f3Smrg                                     Pool == D3DPOOL_SCRATCH);
1147ec681f3Smrg
1157ec681f3Smrg    if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE)
1167ec681f3Smrg        return D3DERR_INVALIDCALL;
1177ec681f3Smrg
1187ec681f3Smrg    if (compressed_format(Format)) {
1197ec681f3Smrg        const unsigned w = util_format_get_blockwidth(pf);
1207ec681f3Smrg        const unsigned h = util_format_get_blockheight(pf);
1217ec681f3Smrg
1227ec681f3Smrg        user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL);
1237ec681f3Smrg    }
1247ec681f3Smrg
1257ec681f3Smrg    info->screen = screen;
1267ec681f3Smrg    info->target = PIPE_TEXTURE_2D;
1277ec681f3Smrg    info->format = pf;
1287ec681f3Smrg    info->width0 = Width;
1297ec681f3Smrg    info->height0 = Height;
1307ec681f3Smrg    info->depth0 = 1;
1317ec681f3Smrg    if (Levels)
1327ec681f3Smrg        info->last_level = Levels - 1;
1337ec681f3Smrg    else
1347ec681f3Smrg        info->last_level = util_logbase2(MAX2(Width, Height));
1357ec681f3Smrg    info->array_size = 1;
1367ec681f3Smrg    info->nr_samples = 0;
1377ec681f3Smrg    info->nr_storage_samples = 0;
1387ec681f3Smrg    info->bind = PIPE_BIND_SAMPLER_VIEW;
1397ec681f3Smrg    info->usage = PIPE_USAGE_DEFAULT;
1407ec681f3Smrg    info->flags = 0;
1417ec681f3Smrg
1427ec681f3Smrg    if (Usage & D3DUSAGE_RENDERTARGET)
1437ec681f3Smrg        info->bind |= PIPE_BIND_RENDER_TARGET;
1447ec681f3Smrg    if (Usage & D3DUSAGE_DEPTHSTENCIL)
1457ec681f3Smrg        info->bind |= PIPE_BIND_DEPTH_STENCIL;
1467ec681f3Smrg
1477ec681f3Smrg    if (Usage & D3DUSAGE_DYNAMIC) {
1487ec681f3Smrg        info->usage = PIPE_USAGE_DYNAMIC;
1497ec681f3Smrg    }
1507ec681f3Smrg
1517ec681f3Smrg    if (Usage & D3DUSAGE_SOFTWAREPROCESSING)
1527ec681f3Smrg        DBG("Application asked for Software Vertex Processing, "
1537ec681f3Smrg            "but this is unimplemented\n");
1547ec681f3Smrg
1557ec681f3Smrg    hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage);
1567ec681f3Smrg    if (FAILED(hr))
1577ec681f3Smrg        return hr;
1587ec681f3Smrg    This->base.pstype = (Height == 1) ? 1 : 0;
1597ec681f3Smrg
1607ec681f3Smrg    if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */
1617ec681f3Smrg        user_buffer = nine_wrap_external_pointer(pParams->device->allocator, (void *)*pSharedHandle);
1627ec681f3Smrg        level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
1637ec681f3Smrg        (void) nine_format_get_size_and_offsets(pf, level_offsets,
1647ec681f3Smrg                                                Width, Height,
1657ec681f3Smrg                                                This->base.level_count-1);
1667ec681f3Smrg    } else if (Pool != D3DPOOL_DEFAULT) {
1677ec681f3Smrg        level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
1687ec681f3Smrg        user_buffer = nine_allocate(pParams->device->allocator,
1697ec681f3Smrg            nine_format_get_size_and_offsets(pf, level_offsets,
1707ec681f3Smrg                                             Width, Height,
1717ec681f3Smrg                                             This->base.level_count-1));
1727ec681f3Smrg        This->managed_buffer = user_buffer;
1737ec681f3Smrg        if (!This->managed_buffer)
1747ec681f3Smrg            return E_OUTOFMEMORY;
1757ec681f3Smrg    }
1767ec681f3Smrg
1777ec681f3Smrg    This->surfaces = CALLOC(This->base.level_count, sizeof(*This->surfaces));
1787ec681f3Smrg    if (!This->surfaces)
1797ec681f3Smrg        return E_OUTOFMEMORY;
1807ec681f3Smrg
1817ec681f3Smrg    /* Create all the surfaces right away.
1827ec681f3Smrg     * They manage backing storage, and transfers (LockRect) are deferred
1837ec681f3Smrg     * to them.
1847ec681f3Smrg     */
1857ec681f3Smrg    sfdesc.Format = Format;
1867ec681f3Smrg    sfdesc.Type = D3DRTYPE_SURFACE;
1877ec681f3Smrg    sfdesc.Usage = Usage;
1887ec681f3Smrg    sfdesc.Pool = Pool;
1897ec681f3Smrg    sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
1907ec681f3Smrg    sfdesc.MultiSampleQuality = 0;
1917ec681f3Smrg
1927ec681f3Smrg    for (l = 0; l < This->base.level_count; ++l) {
1937ec681f3Smrg        sfdesc.Width = u_minify(Width, l);
1947ec681f3Smrg        sfdesc.Height = u_minify(Height, l);
1957ec681f3Smrg        /* Some apps expect the memory to be allocated in
1967ec681f3Smrg         * continous blocks */
1977ec681f3Smrg        user_buffer_for_level = user_buffer ?
1987ec681f3Smrg            nine_suballocate(pParams->device->allocator, user_buffer, level_offsets[l]) : NULL;
1997ec681f3Smrg
2007ec681f3Smrg        hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
2017ec681f3Smrg                              This->base.base.resource, user_buffer_for_level,
2027ec681f3Smrg                              D3DRTYPE_TEXTURE, l, 0,
2037ec681f3Smrg                              &sfdesc, &This->surfaces[l]);
2047ec681f3Smrg        if (FAILED(hr))
2057ec681f3Smrg            return hr;
2067ec681f3Smrg    }
2077ec681f3Smrg
2087ec681f3Smrg    /* Textures start initially dirty */
2097ec681f3Smrg    This->dirty_rect.width = Width;
2107ec681f3Smrg    This->dirty_rect.height = Height;
2117ec681f3Smrg    This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */
2127ec681f3Smrg
2137ec681f3Smrg    if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */
2147ec681f3Smrg        *pSharedHandle = This->surfaces[0]->data;
2157ec681f3Smrg    }
2167ec681f3Smrg
2177ec681f3Smrg    return D3D_OK;
2187ec681f3Smrg}
2197ec681f3Smrg
2207ec681f3Smrgstatic void
2217ec681f3SmrgNineTexture9_dtor( struct NineTexture9 *This )
2227ec681f3Smrg{
2237ec681f3Smrg    bool is_worker = nine_context_is_worker(This->base.base.base.device);
2247ec681f3Smrg    unsigned l;
2257ec681f3Smrg
2267ec681f3Smrg    DBG("This=%p\n", This);
2277ec681f3Smrg
2287ec681f3Smrg    if (This->surfaces) {
2297ec681f3Smrg        /* The surfaces should have 0 references and be unbound now. */
2307ec681f3Smrg        for (l = 0; l < This->base.level_count; ++l)
2317ec681f3Smrg            if (This->surfaces[l])
2327ec681f3Smrg                NineUnknown_Destroy(&This->surfaces[l]->base.base);
2337ec681f3Smrg        FREE(This->surfaces);
2347ec681f3Smrg    }
2357ec681f3Smrg
2367ec681f3Smrg    if (This->managed_buffer) {
2377ec681f3Smrg        if (is_worker)
2387ec681f3Smrg            nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer);
2397ec681f3Smrg        else
2407ec681f3Smrg            nine_free(This->base.base.base.device->allocator, This->managed_buffer);
2417ec681f3Smrg    }
2427ec681f3Smrg
2437ec681f3Smrg    NineBaseTexture9_dtor(&This->base);
2447ec681f3Smrg}
2457ec681f3Smrg
2467ec681f3SmrgHRESULT NINE_WINAPI
2477ec681f3SmrgNineTexture9_GetLevelDesc( struct NineTexture9 *This,
2487ec681f3Smrg                           UINT Level,
2497ec681f3Smrg                           D3DSURFACE_DESC *pDesc )
2507ec681f3Smrg{
2517ec681f3Smrg    DBG("This=%p Level=%d pDesc=%p\n", This, Level, pDesc);
2527ec681f3Smrg
2537ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2547ec681f3Smrg    user_assert(pDesc, D3DERR_INVALIDCALL);
2557ec681f3Smrg
2567ec681f3Smrg    *pDesc = This->surfaces[Level]->desc;
2577ec681f3Smrg
2587ec681f3Smrg    return D3D_OK;
2597ec681f3Smrg}
2607ec681f3Smrg
2617ec681f3SmrgHRESULT NINE_WINAPI
2627ec681f3SmrgNineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
2637ec681f3Smrg                              UINT Level,
2647ec681f3Smrg                              IDirect3DSurface9 **ppSurfaceLevel )
2657ec681f3Smrg{
2667ec681f3Smrg    DBG("This=%p Level=%d ppSurfaceLevel=%p\n", This, Level, ppSurfaceLevel);
2677ec681f3Smrg
2687ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2697ec681f3Smrg    user_assert(ppSurfaceLevel, D3DERR_INVALIDCALL);
2707ec681f3Smrg
2717ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->surfaces[Level]));
2727ec681f3Smrg    *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level];
2737ec681f3Smrg
2747ec681f3Smrg    return D3D_OK;
2757ec681f3Smrg}
2767ec681f3Smrg
2777ec681f3SmrgHRESULT NINE_WINAPI
2787ec681f3SmrgNineTexture9_LockRect( struct NineTexture9 *This,
2797ec681f3Smrg                       UINT Level,
2807ec681f3Smrg                       D3DLOCKED_RECT *pLockedRect,
2817ec681f3Smrg                       const RECT *pRect,
2827ec681f3Smrg                       DWORD Flags )
2837ec681f3Smrg{
2847ec681f3Smrg    DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
2857ec681f3Smrg        This, Level, pLockedRect, pRect, Flags);
2867ec681f3Smrg
2877ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2887ec681f3Smrg
2897ec681f3Smrg    return NineSurface9_LockRect(This->surfaces[Level], pLockedRect,
2907ec681f3Smrg                                 pRect, Flags);
2917ec681f3Smrg}
2927ec681f3Smrg
2937ec681f3SmrgHRESULT NINE_WINAPI
2947ec681f3SmrgNineTexture9_UnlockRect( struct NineTexture9 *This,
2957ec681f3Smrg                         UINT Level )
2967ec681f3Smrg{
2977ec681f3Smrg    DBG("This=%p Level=%u\n", This, Level);
2987ec681f3Smrg
2997ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
3007ec681f3Smrg
3017ec681f3Smrg    return NineSurface9_UnlockRect(This->surfaces[Level]);
3027ec681f3Smrg}
3037ec681f3Smrg
3047ec681f3SmrgHRESULT NINE_WINAPI
3057ec681f3SmrgNineTexture9_AddDirtyRect( struct NineTexture9 *This,
3067ec681f3Smrg                           const RECT *pDirtyRect )
3077ec681f3Smrg{
3087ec681f3Smrg    DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect,
3097ec681f3Smrg        pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0,
3107ec681f3Smrg        pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0);
3117ec681f3Smrg
3127ec681f3Smrg    /* Tracking dirty regions on DEFAULT resources is pointless,
3137ec681f3Smrg     * because we always write to the final storage. Just marked it dirty in
3147ec681f3Smrg     * case we need to generate mip maps.
3157ec681f3Smrg     */
3167ec681f3Smrg    if (This->base.base.pool == D3DPOOL_DEFAULT) {
3177ec681f3Smrg        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) {
3187ec681f3Smrg            This->base.dirty_mip = TRUE;
3197ec681f3Smrg            BASETEX_REGISTER_UPDATE(&This->base);
3207ec681f3Smrg        }
3217ec681f3Smrg        return D3D_OK;
3227ec681f3Smrg    }
3237ec681f3Smrg
3247ec681f3Smrg    if (This->base.base.pool == D3DPOOL_MANAGED) {
3257ec681f3Smrg        This->base.managed.dirty = TRUE;
3267ec681f3Smrg        BASETEX_REGISTER_UPDATE(&This->base);
3277ec681f3Smrg    }
3287ec681f3Smrg
3297ec681f3Smrg    if (!pDirtyRect) {
3307ec681f3Smrg        u_box_origin_2d(This->base.base.info.width0,
3317ec681f3Smrg                        This->base.base.info.height0, &This->dirty_rect);
3327ec681f3Smrg    } else {
3337ec681f3Smrg        if (This->dirty_rect.width == 0) {
3347ec681f3Smrg            rect_to_pipe_box_clamp(&This->dirty_rect, pDirtyRect);
3357ec681f3Smrg        } else {
3367ec681f3Smrg            struct pipe_box box;
3377ec681f3Smrg            rect_to_pipe_box_clamp(&box, pDirtyRect);
3387ec681f3Smrg            u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box);
3397ec681f3Smrg        }
3407ec681f3Smrg        (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect,
3417ec681f3Smrg                             This->base.base.info.width0,
3427ec681f3Smrg                             This->base.base.info.height0);
3437ec681f3Smrg    }
3447ec681f3Smrg    return D3D_OK;
3457ec681f3Smrg}
3467ec681f3Smrg
3477ec681f3SmrgIDirect3DTexture9Vtbl NineTexture9_vtable = {
3487ec681f3Smrg    (void *)NineUnknown_QueryInterface,
3497ec681f3Smrg    (void *)NineUnknown_AddRef,
3507ec681f3Smrg    (void *)NineUnknown_Release,
3517ec681f3Smrg    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
3527ec681f3Smrg    (void *)NineUnknown_SetPrivateData,
3537ec681f3Smrg    (void *)NineUnknown_GetPrivateData,
3547ec681f3Smrg    (void *)NineUnknown_FreePrivateData,
3557ec681f3Smrg    (void *)NineResource9_SetPriority,
3567ec681f3Smrg    (void *)NineResource9_GetPriority,
3577ec681f3Smrg    (void *)NineBaseTexture9_PreLoad,
3587ec681f3Smrg    (void *)NineResource9_GetType,
3597ec681f3Smrg    (void *)NineBaseTexture9_SetLOD,
3607ec681f3Smrg    (void *)NineBaseTexture9_GetLOD,
3617ec681f3Smrg    (void *)NineBaseTexture9_GetLevelCount,
3627ec681f3Smrg    (void *)NineBaseTexture9_SetAutoGenFilterType,
3637ec681f3Smrg    (void *)NineBaseTexture9_GetAutoGenFilterType,
3647ec681f3Smrg    (void *)NineBaseTexture9_GenerateMipSubLevels,
3657ec681f3Smrg    (void *)NineTexture9_GetLevelDesc,
3667ec681f3Smrg    (void *)NineTexture9_GetSurfaceLevel,
3677ec681f3Smrg    (void *)NineTexture9_LockRect,
3687ec681f3Smrg    (void *)NineTexture9_UnlockRect,
3697ec681f3Smrg    (void *)NineTexture9_AddDirtyRect
3707ec681f3Smrg};
3717ec681f3Smrg
3727ec681f3Smrgstatic const GUID *NineTexture9_IIDs[] = {
3737ec681f3Smrg    &IID_IDirect3DTexture9,
3747ec681f3Smrg    &IID_IDirect3DBaseTexture9,
3757ec681f3Smrg    &IID_IDirect3DResource9,
3767ec681f3Smrg    &IID_IUnknown,
3777ec681f3Smrg    NULL
3787ec681f3Smrg};
3797ec681f3Smrg
3807ec681f3SmrgHRESULT
3817ec681f3SmrgNineTexture9_new( struct NineDevice9 *pDevice,
3827ec681f3Smrg                  UINT Width, UINT Height, UINT Levels,
3837ec681f3Smrg                  DWORD Usage,
3847ec681f3Smrg                  D3DFORMAT Format,
3857ec681f3Smrg                  D3DPOOL Pool,
3867ec681f3Smrg                  struct NineTexture9 **ppOut,
3877ec681f3Smrg                  HANDLE *pSharedHandle )
3887ec681f3Smrg{
3897ec681f3Smrg    NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice,
3907ec681f3Smrg                          Width, Height, Levels,
3917ec681f3Smrg                          Usage, Format, Pool, pSharedHandle);
3927ec681f3Smrg}
393