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 "nine_helpers.h"
247ec681f3Smrg#include "nine_shader.h"
257ec681f3Smrg
267ec681f3Smrg#include "pixelshader9.h"
277ec681f3Smrg
287ec681f3Smrg#include "device9.h"
297ec681f3Smrg#include "pipe/p_context.h"
307ec681f3Smrg
317ec681f3Smrg#define DBG_CHANNEL DBG_PIXELSHADER
327ec681f3Smrg
337ec681f3SmrgHRESULT
347ec681f3SmrgNinePixelShader9_ctor( struct NinePixelShader9 *This,
357ec681f3Smrg                       struct NineUnknownParams *pParams,
367ec681f3Smrg                       const DWORD *pFunction, void *cso )
377ec681f3Smrg{
387ec681f3Smrg    struct NineDevice9 *device;
397ec681f3Smrg    struct nine_shader_info info;
407ec681f3Smrg    struct pipe_context *pipe;
417ec681f3Smrg    HRESULT hr;
427ec681f3Smrg
437ec681f3Smrg    DBG("This=%p pParams=%p pFunction=%p cso=%p\n", This, pParams, pFunction, cso);
447ec681f3Smrg
457ec681f3Smrg    hr = NineUnknown_ctor(&This->base, pParams);
467ec681f3Smrg    if (FAILED(hr))
477ec681f3Smrg        return hr;
487ec681f3Smrg
497ec681f3Smrg    if (cso) {
507ec681f3Smrg        This->ff_cso = cso;
517ec681f3Smrg        return D3D_OK;
527ec681f3Smrg    }
537ec681f3Smrg    device = This->base.device;
547ec681f3Smrg
557ec681f3Smrg    info.type = PIPE_SHADER_FRAGMENT;
567ec681f3Smrg    info.byte_code = pFunction;
577ec681f3Smrg    info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16;
587ec681f3Smrg    info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16;
597ec681f3Smrg    info.sampler_mask_shadow = 0x0;
607ec681f3Smrg    info.fetch4 = 0x0;
617ec681f3Smrg    info.sampler_ps1xtypes = 0x0;
627ec681f3Smrg    info.fog_enable = 0;
637ec681f3Smrg    info.projected = 0;
647ec681f3Smrg    info.add_constants_defs.c_combination = NULL;
657ec681f3Smrg    info.add_constants_defs.int_const_added = NULL;
667ec681f3Smrg    info.add_constants_defs.bool_const_added = NULL;
677ec681f3Smrg    info.process_vertices = false;
687ec681f3Smrg    info.swvp_on = false;
697ec681f3Smrg
707ec681f3Smrg    pipe = nine_context_get_pipe_acquire(device);
717ec681f3Smrg    hr = nine_translate_shader(device, &info, pipe);
727ec681f3Smrg    nine_context_get_pipe_release(device);
737ec681f3Smrg    if (FAILED(hr))
747ec681f3Smrg        return hr;
757ec681f3Smrg    This->byte_code.version = info.version;
767ec681f3Smrg
777ec681f3Smrg    This->byte_code.tokens = mem_dup(pFunction, info.byte_size);
787ec681f3Smrg    if (!This->byte_code.tokens)
797ec681f3Smrg        return E_OUTOFMEMORY;
807ec681f3Smrg    This->byte_code.size = info.byte_size;
817ec681f3Smrg
827ec681f3Smrg    This->variant.cso = info.cso;
837ec681f3Smrg    This->variant.const_ranges = info.const_ranges;
847ec681f3Smrg    This->variant.const_used_size = info.const_used_size;
857ec681f3Smrg    This->last_cso = info.cso;
867ec681f3Smrg    This->last_const_ranges = info.const_ranges;
877ec681f3Smrg    This->last_const_used_size = info.const_used_size;
887ec681f3Smrg    This->last_key = 0;
897ec681f3Smrg
907ec681f3Smrg    This->sampler_mask = info.sampler_mask;
917ec681f3Smrg    This->rt_mask = info.rt_mask;
927ec681f3Smrg    This->bumpenvmat_needed = info.bumpenvmat_needed;
937ec681f3Smrg
947ec681f3Smrg    memcpy(This->int_slots_used, info.int_slots_used, sizeof(This->int_slots_used));
957ec681f3Smrg    memcpy(This->bool_slots_used, info.bool_slots_used, sizeof(This->bool_slots_used));
967ec681f3Smrg
977ec681f3Smrg    This->const_int_slots = info.const_int_slots;
987ec681f3Smrg    This->const_bool_slots = info.const_bool_slots;
997ec681f3Smrg
1007ec681f3Smrg    This->c_combinations = NULL;
1017ec681f3Smrg
1027ec681f3Smrg    /* no constant relative addressing for ps */
1037ec681f3Smrg    assert(info.lconstf.data == NULL);
1047ec681f3Smrg    assert(info.lconstf.ranges == NULL);
1057ec681f3Smrg
1067ec681f3Smrg    return D3D_OK;
1077ec681f3Smrg}
1087ec681f3Smrg
1097ec681f3Smrgvoid
1107ec681f3SmrgNinePixelShader9_dtor( struct NinePixelShader9 *This )
1117ec681f3Smrg{
1127ec681f3Smrg    DBG("This=%p\n", This);
1137ec681f3Smrg
1147ec681f3Smrg    if (This->base.device) {
1157ec681f3Smrg        struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device);
1167ec681f3Smrg        struct nine_shader_variant *var = &This->variant;
1177ec681f3Smrg
1187ec681f3Smrg        do {
1197ec681f3Smrg            if (var->cso) {
1207ec681f3Smrg                if (This->base.device->context.cso_shader.ps == var->cso)
1217ec681f3Smrg                    pipe->bind_fs_state(pipe, NULL);
1227ec681f3Smrg                pipe->delete_fs_state(pipe, var->cso);
1237ec681f3Smrg                FREE(var->const_ranges);
1247ec681f3Smrg            }
1257ec681f3Smrg            var = var->next;
1267ec681f3Smrg        } while (var);
1277ec681f3Smrg
1287ec681f3Smrg        if (This->ff_cso) {
1297ec681f3Smrg            if (This->ff_cso == This->base.device->context.cso_shader.ps)
1307ec681f3Smrg                pipe->bind_fs_state(pipe, NULL);
1317ec681f3Smrg            pipe->delete_fs_state(pipe, This->ff_cso);
1327ec681f3Smrg        }
1337ec681f3Smrg    }
1347ec681f3Smrg    nine_shader_variants_free(&This->variant);
1357ec681f3Smrg
1367ec681f3Smrg    nine_shader_constant_combination_free(This->c_combinations);
1377ec681f3Smrg
1387ec681f3Smrg    FREE((void *)This->byte_code.tokens); /* const_cast */
1397ec681f3Smrg
1407ec681f3Smrg    NineUnknown_dtor(&This->base);
1417ec681f3Smrg}
1427ec681f3Smrg
1437ec681f3SmrgHRESULT NINE_WINAPI
1447ec681f3SmrgNinePixelShader9_GetFunction( struct NinePixelShader9 *This,
1457ec681f3Smrg                              void *pData,
1467ec681f3Smrg                              UINT *pSizeOfData )
1477ec681f3Smrg{
1487ec681f3Smrg    DBG("This=%p pData=%p pSizeOfData=%p\n", This, pData, pSizeOfData);
1497ec681f3Smrg
1507ec681f3Smrg    user_assert(pSizeOfData, D3DERR_INVALIDCALL);
1517ec681f3Smrg
1527ec681f3Smrg    if (!pData) {
1537ec681f3Smrg        *pSizeOfData = This->byte_code.size;
1547ec681f3Smrg        return D3D_OK;
1557ec681f3Smrg    }
1567ec681f3Smrg    user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL);
1577ec681f3Smrg
1587ec681f3Smrg    memcpy(pData, This->byte_code.tokens, This->byte_code.size);
1597ec681f3Smrg
1607ec681f3Smrg    return D3D_OK;
1617ec681f3Smrg}
1627ec681f3Smrg
1637ec681f3Smrgvoid *
1647ec681f3SmrgNinePixelShader9_GetVariant( struct NinePixelShader9 *This,
1657ec681f3Smrg                             unsigned **const_ranges,
1667ec681f3Smrg                             unsigned *const_used_size )
1677ec681f3Smrg{
1687ec681f3Smrg    /* GetVariant is called from nine_context, thus we can
1697ec681f3Smrg     * get pipe directly */
1707ec681f3Smrg    struct pipe_context *pipe = This->base.device->context.pipe;
1717ec681f3Smrg    void *cso;
1727ec681f3Smrg    uint64_t key;
1737ec681f3Smrg
1747ec681f3Smrg    key = This->next_key;
1757ec681f3Smrg    if (key == This->last_key) {
1767ec681f3Smrg        *const_ranges = This->last_const_ranges;
1777ec681f3Smrg        *const_used_size = This->last_const_used_size;
1787ec681f3Smrg        return This->last_cso;
1797ec681f3Smrg    }
1807ec681f3Smrg
1817ec681f3Smrg    cso = nine_shader_variant_get(&This->variant, const_ranges, const_used_size, key);
1827ec681f3Smrg    if (!cso) {
1837ec681f3Smrg        struct NineDevice9 *device = This->base.device;
1847ec681f3Smrg        struct nine_shader_info info;
1857ec681f3Smrg        HRESULT hr;
1867ec681f3Smrg
1877ec681f3Smrg        info.type = PIPE_SHADER_FRAGMENT;
1887ec681f3Smrg        info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16;
1897ec681f3Smrg        info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16;
1907ec681f3Smrg        info.byte_code = This->byte_code.tokens;
1917ec681f3Smrg        info.sampler_mask_shadow = key & 0xffff;
1927ec681f3Smrg        /* intended overlap with sampler_mask_shadow */
1937ec681f3Smrg        if (unlikely(This->byte_code.version < 0x20)) {
1947ec681f3Smrg            if (This->byte_code.version < 0x14) {
1957ec681f3Smrg                info.sampler_ps1xtypes = (key >> 4) & 0xff;
1967ec681f3Smrg                info.projected = (key >> 12) & 0xff;
1977ec681f3Smrg            } else {
1987ec681f3Smrg                info.sampler_ps1xtypes = (key >> 6) & 0xfff;
1997ec681f3Smrg                info.projected = 0;
2007ec681f3Smrg            }
2017ec681f3Smrg        } else {
2027ec681f3Smrg            info.sampler_ps1xtypes = 0;
2037ec681f3Smrg            info.projected = 0;
2047ec681f3Smrg        }
2057ec681f3Smrg        info.fog_enable = device->context.rs[D3DRS_FOGENABLE];
2067ec681f3Smrg        info.fog_mode = device->context.rs[D3DRS_FOGTABLEMODE];
2077ec681f3Smrg        info.force_color_in_centroid = (key >> 22) & 1;
2087ec681f3Smrg        info.add_constants_defs.c_combination =
2097ec681f3Smrg            nine_shader_constant_combination_get(This->c_combinations, (key >> 24) & 0xff);
2107ec681f3Smrg        info.add_constants_defs.int_const_added = &This->int_slots_used;
2117ec681f3Smrg        info.add_constants_defs.bool_const_added = &This->bool_slots_used;
2127ec681f3Smrg        info.fetch4 = key >> 32 ;
2137ec681f3Smrg        info.process_vertices = false;
2147ec681f3Smrg        info.swvp_on = false;
2157ec681f3Smrg
2167ec681f3Smrg        hr = nine_translate_shader(This->base.device, &info, pipe);
2177ec681f3Smrg        if (FAILED(hr))
2187ec681f3Smrg            return NULL;
2197ec681f3Smrg        nine_shader_variant_add(&This->variant, key, info.cso,
2207ec681f3Smrg                                info.const_ranges, info.const_used_size);
2217ec681f3Smrg        cso = info.cso;
2227ec681f3Smrg        *const_ranges = info.const_ranges;
2237ec681f3Smrg        *const_used_size = info.const_used_size;
2247ec681f3Smrg    }
2257ec681f3Smrg
2267ec681f3Smrg    This->last_key = key;
2277ec681f3Smrg    This->last_cso = cso;
2287ec681f3Smrg    This->last_const_ranges = *const_ranges;
2297ec681f3Smrg    This->last_const_used_size = *const_used_size;
2307ec681f3Smrg
2317ec681f3Smrg    return cso;
2327ec681f3Smrg}
2337ec681f3Smrg
2347ec681f3SmrgIDirect3DPixelShader9Vtbl NinePixelShader9_vtable = {
2357ec681f3Smrg    (void *)NineUnknown_QueryInterface,
2367ec681f3Smrg    (void *)NineUnknown_AddRef,
2377ec681f3Smrg    (void *)NineUnknown_Release,
2387ec681f3Smrg    (void *)NineUnknown_GetDevice,
2397ec681f3Smrg    (void *)NinePixelShader9_GetFunction
2407ec681f3Smrg};
2417ec681f3Smrg
2427ec681f3Smrgstatic const GUID *NinePixelShader9_IIDs[] = {
2437ec681f3Smrg    &IID_IDirect3DPixelShader9,
2447ec681f3Smrg    &IID_IUnknown,
2457ec681f3Smrg    NULL
2467ec681f3Smrg};
2477ec681f3Smrg
2487ec681f3SmrgHRESULT
2497ec681f3SmrgNinePixelShader9_new( struct NineDevice9 *pDevice,
2507ec681f3Smrg                      struct NinePixelShader9 **ppOut,
2517ec681f3Smrg                      const DWORD *pFunction, void *cso )
2527ec681f3Smrg{
2537ec681f3Smrg    if (cso) { /* ff shader. Needs to start with bind count */
2547ec681f3Smrg        NINE_DEVICE_CHILD_BIND_NEW(PixelShader9, ppOut, pDevice, pFunction, cso);
2557ec681f3Smrg    } else {
2567ec681f3Smrg        NINE_DEVICE_CHILD_NEW(PixelShader9, ppOut, pDevice, pFunction, cso);
2577ec681f3Smrg    }
2587ec681f3Smrg}
259