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 "cubetexture9.h"
277ec681f3Smrg#include "nine_memory_helper.h"
287ec681f3Smrg#include "nine_helpers.h"
297ec681f3Smrg#include "nine_pipe.h"
307ec681f3Smrg
317ec681f3Smrg#define DBG_CHANNEL DBG_CUBETEXTURE
327ec681f3Smrg
337ec681f3Smrg
347ec681f3Smrgstatic HRESULT
357ec681f3SmrgNineCubeTexture9_ctor( struct NineCubeTexture9 *This,
367ec681f3Smrg                       struct NineUnknownParams *pParams,
377ec681f3Smrg                       UINT EdgeLength, UINT Levels,
387ec681f3Smrg                       DWORD Usage,
397ec681f3Smrg                       D3DFORMAT Format,
407ec681f3Smrg                       D3DPOOL Pool,
417ec681f3Smrg                       HANDLE *pSharedHandle )
427ec681f3Smrg{
437ec681f3Smrg    struct pipe_resource *info = &This->base.base.info;
447ec681f3Smrg    struct pipe_screen *screen = pParams->device->screen;
457ec681f3Smrg    enum pipe_format pf;
467ec681f3Smrg    unsigned i, l, f, offset, face_size = 0;
477ec681f3Smrg    unsigned *level_offsets = NULL;
487ec681f3Smrg    D3DSURFACE_DESC sfdesc;
497ec681f3Smrg    struct nine_allocation *p;
507ec681f3Smrg    HRESULT hr;
517ec681f3Smrg
527ec681f3Smrg    DBG("This=%p pParams=%p EdgeLength=%u Levels=%u Usage=%d "
537ec681f3Smrg        "Format=%d Pool=%d pSharedHandle=%p\n",
547ec681f3Smrg        This, pParams, EdgeLength, Levels, Usage,
557ec681f3Smrg        Format, Pool, pSharedHandle);
567ec681f3Smrg
577ec681f3Smrg    This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */
587ec681f3Smrg
597ec681f3Smrg    user_assert(EdgeLength, D3DERR_INVALIDCALL);
607ec681f3Smrg
617ec681f3Smrg    /* user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); */
627ec681f3Smrg    user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */
637ec681f3Smrg
647ec681f3Smrg    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
657ec681f3Smrg                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
667ec681f3Smrg
677ec681f3Smrg    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
687ec681f3Smrg        Levels = 0;
697ec681f3Smrg
707ec681f3Smrg    pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_CUBE, 0,
717ec681f3Smrg                                     PIPE_BIND_SAMPLER_VIEW, FALSE,
727ec681f3Smrg                                     Pool == D3DPOOL_SCRATCH);
737ec681f3Smrg
747ec681f3Smrg    if (pf == PIPE_FORMAT_NONE)
757ec681f3Smrg        return D3DERR_INVALIDCALL;
767ec681f3Smrg
777ec681f3Smrg    if (compressed_format(Format)) {
787ec681f3Smrg        const unsigned w = util_format_get_blockwidth(pf);
797ec681f3Smrg        const unsigned h = util_format_get_blockheight(pf);
807ec681f3Smrg
817ec681f3Smrg        user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL);
827ec681f3Smrg    }
837ec681f3Smrg
847ec681f3Smrg    info->screen = pParams->device->screen;
857ec681f3Smrg    info->target = PIPE_TEXTURE_CUBE;
867ec681f3Smrg    info->format = pf;
877ec681f3Smrg    info->width0 = EdgeLength;
887ec681f3Smrg    info->height0 = EdgeLength;
897ec681f3Smrg    info->depth0 = 1;
907ec681f3Smrg    if (Levels)
917ec681f3Smrg        info->last_level = Levels - 1;
927ec681f3Smrg    else
937ec681f3Smrg        info->last_level = util_logbase2(EdgeLength);
947ec681f3Smrg    info->array_size = 6;
957ec681f3Smrg    info->nr_samples = 0;
967ec681f3Smrg    info->nr_storage_samples = 0;
977ec681f3Smrg    info->bind = PIPE_BIND_SAMPLER_VIEW;
987ec681f3Smrg    info->usage = PIPE_USAGE_DEFAULT;
997ec681f3Smrg    info->flags = 0;
1007ec681f3Smrg
1017ec681f3Smrg    if (Usage & D3DUSAGE_RENDERTARGET)
1027ec681f3Smrg        info->bind |= PIPE_BIND_RENDER_TARGET;
1037ec681f3Smrg    if (Usage & D3DUSAGE_DEPTHSTENCIL)
1047ec681f3Smrg        info->bind |= PIPE_BIND_DEPTH_STENCIL;
1057ec681f3Smrg
1067ec681f3Smrg    if (Usage & D3DUSAGE_DYNAMIC) {
1077ec681f3Smrg        info->usage = PIPE_USAGE_DYNAMIC;
1087ec681f3Smrg    }
1097ec681f3Smrg    if (Usage & D3DUSAGE_SOFTWAREPROCESSING)
1107ec681f3Smrg        DBG("Application asked for Software Vertex Processing, "
1117ec681f3Smrg            "but this is unimplemented\n");
1127ec681f3Smrg
1137ec681f3Smrg    hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_CUBETEXTURE,
1147ec681f3Smrg                               Format, Pool, Usage);
1157ec681f3Smrg    if (FAILED(hr))
1167ec681f3Smrg        return hr;
1177ec681f3Smrg    This->base.pstype = 2;
1187ec681f3Smrg
1197ec681f3Smrg    if (Pool != D3DPOOL_DEFAULT) {
1207ec681f3Smrg        level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
1217ec681f3Smrg        face_size = nine_format_get_size_and_offsets(pf, level_offsets,
1227ec681f3Smrg                                                     EdgeLength, EdgeLength,
1237ec681f3Smrg                                                     This->base.level_count-1);
1247ec681f3Smrg        This->managed_buffer = nine_allocate(pParams->device->allocator, 6 * face_size);
1257ec681f3Smrg        if (!This->managed_buffer)
1267ec681f3Smrg            return E_OUTOFMEMORY;
1277ec681f3Smrg    }
1287ec681f3Smrg
1297ec681f3Smrg    This->surfaces = CALLOC(6 * This->base.level_count, sizeof(*This->surfaces));
1307ec681f3Smrg    if (!This->surfaces)
1317ec681f3Smrg        return E_OUTOFMEMORY;
1327ec681f3Smrg
1337ec681f3Smrg    /* Create all the surfaces right away.
1347ec681f3Smrg     * They manage backing storage, and transfers (LockRect) are deferred
1357ec681f3Smrg     * to them.
1367ec681f3Smrg     */
1377ec681f3Smrg    sfdesc.Format = Format;
1387ec681f3Smrg    sfdesc.Type = D3DRTYPE_SURFACE;
1397ec681f3Smrg    sfdesc.Usage = Usage;
1407ec681f3Smrg    sfdesc.Pool = Pool;
1417ec681f3Smrg    sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
1427ec681f3Smrg    sfdesc.MultiSampleQuality = 0;
1437ec681f3Smrg    /* We allocate the memory for the surfaces as continous blocks.
1447ec681f3Smrg     * This is the expected behaviour, however we haven't tested for
1457ec681f3Smrg     * cube textures in which order the faces/levels should be in memory
1467ec681f3Smrg     */
1477ec681f3Smrg    for (f = 0; f < 6; f++) {
1487ec681f3Smrg        offset = f * face_size;
1497ec681f3Smrg        for (l = 0; l < This->base.level_count; l++) {
1507ec681f3Smrg            sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l);
1517ec681f3Smrg            p = This->managed_buffer ?
1527ec681f3Smrg                nine_suballocate(pParams->device->allocator, This->managed_buffer, offset + level_offsets[l]) : NULL;
1537ec681f3Smrg
1547ec681f3Smrg            hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
1557ec681f3Smrg                                  This->base.base.resource, p, D3DRTYPE_CUBETEXTURE,
1567ec681f3Smrg                                  l, f, &sfdesc, &This->surfaces[f + 6 * l]);
1577ec681f3Smrg            if (FAILED(hr))
1587ec681f3Smrg                return hr;
1597ec681f3Smrg        }
1607ec681f3Smrg    }
1617ec681f3Smrg
1627ec681f3Smrg    for (i = 0; i < 6; ++i) {
1637ec681f3Smrg        /* Textures start initially dirty */
1647ec681f3Smrg        This->dirty_rect[i].width = EdgeLength;
1657ec681f3Smrg        This->dirty_rect[i].height = EdgeLength;
1667ec681f3Smrg        This->dirty_rect[i].depth = 1;
1677ec681f3Smrg    }
1687ec681f3Smrg
1697ec681f3Smrg    return D3D_OK;
1707ec681f3Smrg}
1717ec681f3Smrg
1727ec681f3Smrgstatic void
1737ec681f3SmrgNineCubeTexture9_dtor( struct NineCubeTexture9 *This )
1747ec681f3Smrg{
1757ec681f3Smrg    unsigned i;
1767ec681f3Smrg    bool is_worker = nine_context_is_worker(This->base.base.base.device);
1777ec681f3Smrg
1787ec681f3Smrg    DBG("This=%p\n", This);
1797ec681f3Smrg
1807ec681f3Smrg    if (This->surfaces) {
1817ec681f3Smrg        for (i = 0; i < This->base.level_count * 6; ++i)
1827ec681f3Smrg            if (This->surfaces[i])
1837ec681f3Smrg                NineUnknown_Destroy(&This->surfaces[i]->base.base);
1847ec681f3Smrg        FREE(This->surfaces);
1857ec681f3Smrg    }
1867ec681f3Smrg
1877ec681f3Smrg    if (This->managed_buffer) {
1887ec681f3Smrg        if (is_worker)
1897ec681f3Smrg            nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer);
1907ec681f3Smrg        else
1917ec681f3Smrg            nine_free(This->base.base.base.device->allocator, This->managed_buffer);
1927ec681f3Smrg    }
1937ec681f3Smrg
1947ec681f3Smrg    NineBaseTexture9_dtor(&This->base);
1957ec681f3Smrg}
1967ec681f3Smrg
1977ec681f3SmrgHRESULT NINE_WINAPI
1987ec681f3SmrgNineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This,
1997ec681f3Smrg                               UINT Level,
2007ec681f3Smrg                               D3DSURFACE_DESC *pDesc )
2017ec681f3Smrg{
2027ec681f3Smrg    DBG("This=%p Level=%u pDesc=%p\n", This, Level, pDesc);
2037ec681f3Smrg
2047ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2057ec681f3Smrg
2067ec681f3Smrg    *pDesc = This->surfaces[Level * 6]->desc;
2077ec681f3Smrg
2087ec681f3Smrg    return D3D_OK;
2097ec681f3Smrg}
2107ec681f3Smrg
2117ec681f3SmrgHRESULT NINE_WINAPI
2127ec681f3SmrgNineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This,
2137ec681f3Smrg                                    D3DCUBEMAP_FACES FaceType,
2147ec681f3Smrg                                    UINT Level,
2157ec681f3Smrg                                    IDirect3DSurface9 **ppCubeMapSurface )
2167ec681f3Smrg{
2177ec681f3Smrg    const unsigned s = Level * 6 + FaceType;
2187ec681f3Smrg
2197ec681f3Smrg    DBG("This=%p FaceType=%d Level=%u ppCubeMapSurface=%p\n",
2207ec681f3Smrg        This, FaceType, Level, ppCubeMapSurface);
2217ec681f3Smrg
2227ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2237ec681f3Smrg    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
2247ec681f3Smrg
2257ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->surfaces[s]));
2267ec681f3Smrg    *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s];
2277ec681f3Smrg
2287ec681f3Smrg    return D3D_OK;
2297ec681f3Smrg}
2307ec681f3Smrg
2317ec681f3SmrgHRESULT NINE_WINAPI
2327ec681f3SmrgNineCubeTexture9_LockRect( struct NineCubeTexture9 *This,
2337ec681f3Smrg                           D3DCUBEMAP_FACES FaceType,
2347ec681f3Smrg                           UINT Level,
2357ec681f3Smrg                           D3DLOCKED_RECT *pLockedRect,
2367ec681f3Smrg                           const RECT *pRect,
2377ec681f3Smrg                           DWORD Flags )
2387ec681f3Smrg{
2397ec681f3Smrg    const unsigned s = Level * 6 + FaceType;
2407ec681f3Smrg
2417ec681f3Smrg    DBG("This=%p FaceType=%d Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
2427ec681f3Smrg        This, FaceType, Level, pLockedRect, pRect, Flags);
2437ec681f3Smrg
2447ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2457ec681f3Smrg    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
2467ec681f3Smrg
2477ec681f3Smrg    return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags);
2487ec681f3Smrg}
2497ec681f3Smrg
2507ec681f3SmrgHRESULT NINE_WINAPI
2517ec681f3SmrgNineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This,
2527ec681f3Smrg                             D3DCUBEMAP_FACES FaceType,
2537ec681f3Smrg                             UINT Level )
2547ec681f3Smrg{
2557ec681f3Smrg    const unsigned s = Level * 6 + FaceType;
2567ec681f3Smrg
2577ec681f3Smrg    DBG("This=%p FaceType=%d Level=%u\n", This, FaceType, Level);
2587ec681f3Smrg
2597ec681f3Smrg    user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
2607ec681f3Smrg    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
2617ec681f3Smrg
2627ec681f3Smrg    return NineSurface9_UnlockRect(This->surfaces[s]);
2637ec681f3Smrg}
2647ec681f3Smrg
2657ec681f3SmrgHRESULT NINE_WINAPI
2667ec681f3SmrgNineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
2677ec681f3Smrg                               D3DCUBEMAP_FACES FaceType,
2687ec681f3Smrg                               const RECT *pDirtyRect )
2697ec681f3Smrg{
2707ec681f3Smrg    DBG("This=%p FaceType=%d pDirtyRect=%p\n", This, FaceType, pDirtyRect);
2717ec681f3Smrg
2727ec681f3Smrg    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
2737ec681f3Smrg
2747ec681f3Smrg    if (This->base.base.pool != D3DPOOL_MANAGED) {
2757ec681f3Smrg        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) {
2767ec681f3Smrg            This->base.dirty_mip = TRUE;
2777ec681f3Smrg            BASETEX_REGISTER_UPDATE(&This->base);
2787ec681f3Smrg        }
2797ec681f3Smrg        return D3D_OK;
2807ec681f3Smrg    }
2817ec681f3Smrg
2827ec681f3Smrg    if (This->base.base.pool == D3DPOOL_MANAGED) {
2837ec681f3Smrg        This->base.managed.dirty = TRUE;
2847ec681f3Smrg        BASETEX_REGISTER_UPDATE(&This->base);
2857ec681f3Smrg    }
2867ec681f3Smrg
2877ec681f3Smrg    if (!pDirtyRect) {
2887ec681f3Smrg        u_box_origin_2d(This->base.base.info.width0,
2897ec681f3Smrg                        This->base.base.info.height0,
2907ec681f3Smrg                        &This->dirty_rect[FaceType]);
2917ec681f3Smrg    } else {
2927ec681f3Smrg        if (This->dirty_rect[FaceType].width == 0) {
2937ec681f3Smrg            rect_to_pipe_box_clamp(&This->dirty_rect[FaceType], pDirtyRect);
2947ec681f3Smrg        } else {
2957ec681f3Smrg            struct pipe_box box;
2967ec681f3Smrg            rect_to_pipe_box_clamp(&box, pDirtyRect);
2977ec681f3Smrg            u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType],
2987ec681f3Smrg                           &box);
2997ec681f3Smrg        }
3007ec681f3Smrg        (void) u_box_clip_2d(&This->dirty_rect[FaceType],
3017ec681f3Smrg                             &This->dirty_rect[FaceType],
3027ec681f3Smrg                             This->base.base.info.width0,
3037ec681f3Smrg                             This->base.base.info.height0);
3047ec681f3Smrg    }
3057ec681f3Smrg    return D3D_OK;
3067ec681f3Smrg}
3077ec681f3Smrg
3087ec681f3SmrgIDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = {
3097ec681f3Smrg    (void *)NineUnknown_QueryInterface,
3107ec681f3Smrg    (void *)NineUnknown_AddRef,
3117ec681f3Smrg    (void *)NineUnknown_Release,
3127ec681f3Smrg    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
3137ec681f3Smrg    (void *)NineUnknown_SetPrivateData,
3147ec681f3Smrg    (void *)NineUnknown_GetPrivateData,
3157ec681f3Smrg    (void *)NineUnknown_FreePrivateData,
3167ec681f3Smrg    (void *)NineResource9_SetPriority,
3177ec681f3Smrg    (void *)NineResource9_GetPriority,
3187ec681f3Smrg    (void *)NineBaseTexture9_PreLoad,
3197ec681f3Smrg    (void *)NineResource9_GetType,
3207ec681f3Smrg    (void *)NineBaseTexture9_SetLOD,
3217ec681f3Smrg    (void *)NineBaseTexture9_GetLOD,
3227ec681f3Smrg    (void *)NineBaseTexture9_GetLevelCount,
3237ec681f3Smrg    (void *)NineBaseTexture9_SetAutoGenFilterType,
3247ec681f3Smrg    (void *)NineBaseTexture9_GetAutoGenFilterType,
3257ec681f3Smrg    (void *)NineBaseTexture9_GenerateMipSubLevels,
3267ec681f3Smrg    (void *)NineCubeTexture9_GetLevelDesc,
3277ec681f3Smrg    (void *)NineCubeTexture9_GetCubeMapSurface,
3287ec681f3Smrg    (void *)NineCubeTexture9_LockRect,
3297ec681f3Smrg    (void *)NineCubeTexture9_UnlockRect,
3307ec681f3Smrg    (void *)NineCubeTexture9_AddDirtyRect
3317ec681f3Smrg};
3327ec681f3Smrg
3337ec681f3Smrgstatic const GUID *NineCubeTexture9_IIDs[] = {
3347ec681f3Smrg    &IID_IDirect3DCubeTexture9,
3357ec681f3Smrg    &IID_IDirect3DBaseTexture9,
3367ec681f3Smrg    &IID_IDirect3DResource9,
3377ec681f3Smrg    &IID_IUnknown,
3387ec681f3Smrg    NULL
3397ec681f3Smrg};
3407ec681f3Smrg
3417ec681f3SmrgHRESULT
3427ec681f3SmrgNineCubeTexture9_new( struct NineDevice9 *pDevice,
3437ec681f3Smrg                      UINT EdgeLength, UINT Levels,
3447ec681f3Smrg                      DWORD Usage,
3457ec681f3Smrg                      D3DFORMAT Format,
3467ec681f3Smrg                      D3DPOOL Pool,
3477ec681f3Smrg                      struct NineCubeTexture9 **ppOut,
3487ec681f3Smrg                      HANDLE *pSharedHandle )
3497ec681f3Smrg{
3507ec681f3Smrg    NINE_DEVICE_CHILD_NEW(CubeTexture9, ppOut, pDevice,
3517ec681f3Smrg                          EdgeLength, Levels,
3527ec681f3Smrg                          Usage, Format, Pool, pSharedHandle);
3537ec681f3Smrg}
354