diff options
author | Joakim Sindholt <[email protected]> | 2011-08-04 15:14:06 +0200 |
---|---|---|
committer | Emil Velikov <[email protected]> | 2014-11-18 02:29:26 +0000 |
commit | b46e80ae6004b7dfcbd8bc4e32ff51af36defadf (patch) | |
tree | 213a9f29b3804e29d0de3a83d9d18c0ff75fd40e /src/gallium | |
parent | ff97fbd9e9c88d4d0a3f8adefb69682941f1927d (diff) |
nine: Add state tracker nine for Direct3D9 (v3)
Work of Joakim Sindholt (zhasha) and Christoph Bumiller (chrisbmr).
DRI3 port done by Axel Davy (mannerov).
v2: - nine_debug.c: klass extended from 32 chars to 96 (for sure) by glennk
- Nine improvements by Axel Davy (which also fixed some wine tests)
- by Emil Velikov:
- convert to static/shared drivers
- Sort and cleanup the includes
- Use AM_CPPFLAGS for the defines
- Add the linker garbage collector
- Restrict the exported symbols (think llvm)
v3: - small nine fixes
- build system improvements by Emil Velikov
v4: [Emil Velikov]
- Do no link against libudev. No longer needed.
Acked-by: Jose Fonseca <[email protected]>
Reviewed-by: Marek Olšák <[email protected]>
Reviewed-by: Axel Davy <[email protected]>
Signed-off-by: David Heidelberg <[email protected]>
(cherry picked from commit fdd96578ef2dfe9c4ad5aab5858036298d444a64)
[Emil Velikov: use correct ureg_property* functions]
Signed-off-by: Emil Velikov <[email protected]>
Diffstat (limited to 'src/gallium')
80 files changed, 28388 insertions, 0 deletions
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am index ca10c0ef329..1c1bab8b5fc 100644 --- a/src/gallium/Makefile.am +++ b/src/gallium/Makefile.am @@ -166,6 +166,10 @@ if HAVE_ST_XVMC SUBDIRS += state_trackers/xvmc targets/xvmc endif +if HAVE_ST_NINE +SUBDIRS += state_trackers/nine targets/d3dadapter9 +endif + ## ## Don't forget to bundle the remaining (non autotools) state-trackers/targets ## diff --git a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h index 8a144db09c3..d8cee2b2917 100644 --- a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h +++ b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h @@ -91,6 +91,34 @@ drisw_create_screen(struct drisw_loader_funcs *lf) return screen; } #endif // DRI_TARGET + +#if defined(NINE_TARGET) +#include "sw/wrapper/wrapper_sw_winsys.h" +#include "target-helpers/inline_debug_helper.h" + +extern struct pipe_screen *ninesw_create_screen(struct pipe_screen *screen); + +INLINE struct pipe_screen * +ninesw_create_screen(struct pipe_screen *pscreen) +{ + struct sw_winsys *winsys = NULL; + struct pipe_screen *screen = NULL; + + winsys = wrapper_sw_winsys_wrap_pipe_screen(pscreen); + if (winsys == NULL) + return NULL; + + screen = sw_screen_create(winsys); + if (screen == NULL) { + winsys->destroy(winsys); + return NULL; + } + + screen = debug_screen_wrap(screen); + return screen; +} +#endif // NINE_TARGET + #endif // GALLIUM_SOFTPIPE diff --git a/src/gallium/state_trackers/nine/Makefile.am b/src/gallium/state_trackers/nine/Makefile.am new file mode 100644 index 00000000000..c0c75b34c59 --- /dev/null +++ b/src/gallium/state_trackers/nine/Makefile.am @@ -0,0 +1,13 @@ +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + -I$(top_srcdir)/include/D3D9 \ + $(GALLIUM_CFLAGS) \ + $(VISIBILITY_CFLAGS) + +noinst_LTLIBRARIES = libninetracker.la + +libninetracker_la_SOURCES = $(C_SOURCES) + +EXTRA_DIST = README diff --git a/src/gallium/state_trackers/nine/Makefile.sources b/src/gallium/state_trackers/nine/Makefile.sources new file mode 100644 index 00000000000..b8219613f6c --- /dev/null +++ b/src/gallium/state_trackers/nine/Makefile.sources @@ -0,0 +1,71 @@ +C_SOURCES := \ + adapter9.c \ + adapter9.h \ + authenticatedchannel9.c \ + authenticatedchannel9.h \ + basetexture9.c \ + basetexture9.h \ + cryptosession9.c \ + cryptosession9.h \ + cubetexture9.c \ + cubetexture9.h \ + device9.c \ + device9.h \ + device9ex.c \ + device9ex.h \ + device9video.c \ + device9video.h \ + guid.c \ + guid.h \ + indexbuffer9.c \ + indexbuffer9.h \ + iunknown.c \ + iunknown.h \ + nine_debug.c \ + nine_debug.h \ + nine_defines.h \ + nine_dump.c \ + nine_dump.h \ + nineexoverlayextension.c \ + nineexoverlayextension.h \ + nine_ff.c \ + nine_ff.h \ + nine_helpers.c \ + nine_helpers.h \ + nine_lock.c \ + nine_lock.h \ + nine_pdata.h \ + nine_pipe.c \ + nine_pipe.h \ + nine_quirk.c \ + nine_quirk.h \ + nine_shader.c \ + nine_shader.h \ + nine_state.c \ + nine_state.h \ + pixelshader9.c \ + pixelshader9.h \ + query9.c \ + query9.h \ + resource9.c \ + resource9.h \ + stateblock9.c \ + stateblock9.h \ + surface9.c \ + surface9.h \ + swapchain9.c \ + swapchain9ex.c \ + swapchain9ex.h \ + swapchain9.h \ + texture9.c \ + texture9.h \ + vertexbuffer9.c \ + vertexbuffer9.h \ + vertexdeclaration9.c \ + vertexdeclaration9.h \ + vertexshader9.c \ + vertexshader9.h \ + volume9.c \ + volume9.h \ + volumetexture9.c \ + volumetexture9.h diff --git a/src/gallium/state_trackers/nine/README b/src/gallium/state_trackers/nine/README new file mode 100644 index 00000000000..f10045c0deb --- /dev/null +++ b/src/gallium/state_trackers/nine/README @@ -0,0 +1,78 @@ +Quickstart Guide + +*** Configure and build mesa +CFLAGS="-m32" CXXFLAGS="-m32" ./autogen.sh --prefix=/usr \ + --with-gallium-drivers=nouveau,r600,swrast --enable-nine \ + --with-gallium-driver-dir="`pwd`/src/gallium/targets/pipe-loader/.libs" \ + --enable-debug --enable-texture-float --with-dri-drivers= --disable-dri \ + --disable-opengl --disable-egl --disable-vdpau --disable-xvmc --disable-gbm \ + --disable-gallium-llvm +make + +*** Then we create some symlinks to mesa: +ln -s "`pwd`/lib/gallium/libd3dadapter9.so.0.0.0" /usr/lib/ +ln -s "`pwd`/lib/gallium/libd3dadapter9.so.0" /usr/lib/ +ln -s "`pwd`/lib/gallium/libd3dadapter9.so" /usr/lib/ +ln -s "`pwd`/include/d3dadapter" /usr/include/ + +*** Clone and build a patched wine +git clone [email protected]:iXit/wine.git +./configure +make + +*** And finally we create some symlinks to our patched wine files: +for f in d3d9.dll gdi32.dll user32.dll wineps.drv winex11.drv; +do + mv /usr/lib/wine/$f.so /usr/lib/wine/$f.so.old + ln -s "`pwd`/dlls/`basename -s .dll $f`/$f.so" /usr/lib/wine/ +done + +*** Activating it within wine +regedit +Navigate to HKCU\Software\Wine\Direct3D +If it's not there, create it +Create a new DWORD value called UseNative +Set its value to 1 + +Every Direct3D9 program will now try using nine before wined3d + +If you want to selectively enable it per-exe instead, use the key: +HKCU\Software\Wine\AppDefaults\app.exe\Direct3D\UseNative +where app.exe is the name of your .exe file + + +*** HOW IT WORKS *** + +Nine implements the full IDirect3DDevice9 COM interface and a custom COM +interface called ID3DAdapter9 which is used to implement a final IDirect3D9Ex +COM interface. +ID3DAdapter9 is completely devoid of window system code, meaning this can be +provided by wine, Xlib, Wayland, etc. It's inadvisible to write a non-Windows +backend though, as we don't want to encourage linux developers to use this API. + +The state tracker is compiled, along with pipe-loader, into a library called +libd3dadapter9.so. This library loads pipe_[driver].so drivers on demand and +exports a single symbol for getting a subsystem driver. Currently only DRM is +supported. +This library is then linked to the library implementing the IDirect3D9[Ex] +interface and the actual Direct3D9 entry points (Direct3DCreate9[Ex]) + +The implementation of IDirect3D9[Ex] lies within wine and coexists with +wined3d. It's loaded on demand and so if it's not there, it doesn't have any +drivers or something else is wrong, d3d9.dll will automatically revert to using +wined3d. +Whether or not it's even tried is determined by 2 DWORD registry keys. +> HKCU\Software\Wine\Direct3D\UseNative +> HKCU\Software\Wine\AppDefaults\app.exe\Direct3D\UseNative +The former is the global on-switch. The latter is per-exe. + +The driver search path can be set at configure time with +--with-gallium-driver-dir and overridden at runtime with D3D9_DRIVERS_PATH. +Debugging information can be gotten with the WINEDEBUG channels d3d9 and +d3dadapter, and state_tracker debug information can be gotten with NINE_DEBUG. +Help on NINE_DEBUG is shown through NINE_DEBUG=help + +Finally, the ID3DPresent[Group] and ID3DAdapter9 interfaces are not set in +stone, so feel free to hack on those as well as st/nine. + +Happy Hacking! diff --git a/src/gallium/state_trackers/nine/adapter9.c b/src/gallium/state_trackers/nine/adapter9.c new file mode 100644 index 00000000000..8d574deeca3 --- /dev/null +++ b/src/gallium/state_trackers/nine/adapter9.c @@ -0,0 +1,1091 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "adapter9.h" +#include "device9ex.h" +#include "nine_helpers.h" +#include "nine_defines.h" +#include "nine_pipe.h" +#include "nine_dump.h" +#include "util/u_math.h" +#include "util/u_format.h" +#include "util/u_dump.h" + +#include "pipe/p_screen.h" + +#define DBG_CHANNEL DBG_ADAPTER + +HRESULT +NineAdapter9_ctor( struct NineAdapter9 *This, + struct NineUnknownParams *pParams, + struct d3dadapter9_context *pCTX ) +{ + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) { return hr; } + + DBG("This=%p pParams=%p pCTX=%p\n", This, pParams, pCTX); + nine_dump_D3DADAPTER_IDENTIFIER9(DBG_CHANNEL, &pCTX->identifier); + + This->ctx = pCTX; + if (!This->ctx->hal->get_param(This->ctx->hal, PIPE_CAP_CLIP_HALFZ)) { + ERR("Driver doesn't support d3d9 coordinates\n"); + return D3DERR_DRIVERINTERNALERROR; + } + if (This->ctx->ref && + !This->ctx->ref->get_param(This->ctx->ref, PIPE_CAP_CLIP_HALFZ)) { + ERR("Warning: Sotware rendering driver doesn't support d3d9 coordinates\n"); + } + + return D3D_OK; +} + +void +NineAdapter9_dtor( struct NineAdapter9 *This ) +{ + struct d3dadapter9_context *ctx = This->ctx; + + DBG("This=%p\n", This); + + NineUnknown_dtor(&This->base); + + /* special case, call backend-specific dtor AFTER destroying this object + * completely. */ + if (ctx) { + if (ctx->destroy) { ctx->destroy(ctx); } + } +} + +static HRESULT +NineAdapter9_GetScreen( struct NineAdapter9 *This, + D3DDEVTYPE DevType, + struct pipe_screen **ppScreen ) +{ + const char *force_sw = getenv("D3D_ALWAYS_SOFTWARE"); + switch (DevType) { + case D3DDEVTYPE_HAL: + if (force_sw && !strcmp(force_sw, "1") && This->ctx->ref) { + *ppScreen = This->ctx->ref; + break; + } + *ppScreen = This->ctx->hal; + break; + + case D3DDEVTYPE_REF: + case D3DDEVTYPE_NULLREF: + case D3DDEVTYPE_SW: + if (force_sw && !strcmp(force_sw, "0")) { + *ppScreen = This->ctx->hal; + break; + } + *ppScreen = This->ctx->ref; + break; + + default: + user_assert(!"Invalid device type", D3DERR_INVALIDCALL); + } + + if (!*ppScreen) { return D3DERR_NOTAVAILABLE; } + + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_GetAdapterIdentifier( struct NineAdapter9 *This, + DWORD Flags, + D3DADAPTER_IDENTIFIER9 *pIdentifier ) +{ + DBG("This=%p Flags=%x pIdentifier=%p\n", This, Flags, pIdentifier); + + /* regarding flags, MSDN has this to say: + * Flags sets the WHQLLevel member of D3DADAPTER_IDENTIFIER9. Flags can be + * set to either 0 or D3DENUM_WHQL_LEVEL. If D3DENUM_WHQL_LEVEL is + * specified, this call can connect to the Internet to download new + * Microsoft Windows Hardware Quality Labs (WHQL) certificates. + * so let's just ignore it. */ + *pIdentifier = This->ctx->identifier; + return D3D_OK; +} + +static INLINE boolean +backbuffer_format( D3DFORMAT dfmt, + D3DFORMAT bfmt, + boolean win ) +{ + if (dfmt == D3DFMT_A2R10G10B10 && win) { return FALSE; } + + if ((dfmt == D3DFMT_A2R10G10B10 && bfmt == dfmt) || + (dfmt == D3DFMT_X8R8G8B8 && (bfmt == dfmt || + bfmt == D3DFMT_A8R8G8B8)) || + (dfmt == D3DFMT_X1R5G5B5 && (bfmt == dfmt || + bfmt == D3DFMT_A1R5G5B5)) || + (dfmt == D3DFMT_R5G6B5 && bfmt == dfmt)) { + return TRUE; + } + + return FALSE; +} + +HRESULT WINAPI +NineAdapter9_CheckDeviceType( struct NineAdapter9 *This, + D3DDEVTYPE DevType, + D3DFORMAT AdapterFormat, + D3DFORMAT BackBufferFormat, + BOOL bWindowed ) +{ + struct pipe_screen *screen; + enum pipe_format dfmt, bfmt; + HRESULT hr; + + DBG("This=%p DevType=%s AdapterFormat=%s BackBufferFormat=%s " + "bWindowed=%i\n", This, nine_D3DDEVTYPE_to_str(DevType), + d3dformat_to_string(AdapterFormat), + d3dformat_to_string(BackBufferFormat), bWindowed); + + user_assert(backbuffer_format(AdapterFormat, BackBufferFormat, bWindowed), + D3DERR_NOTAVAILABLE); + + hr = NineAdapter9_GetScreen(This, DevType, &screen); + if (FAILED(hr)) { return hr; } + + dfmt = d3d9_to_pipe_format(AdapterFormat); + bfmt = d3d9_to_pipe_format(BackBufferFormat); + if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) { + DBG("Invalid Adapter/BackBufferFormat.\n"); + return D3DERR_NOTAVAILABLE; + } + + if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 1, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED) || + !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 1, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED)) { + DBG("Unsupported Adapter/BackBufferFormat.\n"); + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +static INLINE boolean +display_format( D3DFORMAT fmt, + boolean win ) +{ + /* http://msdn.microsoft.com/en-us/library/bb172558(v=VS.85).aspx#BackBuffer_or_Display_Formats */ + static const D3DFORMAT allowed[] = { + D3DFMT_A2R10G10B10, + D3DFMT_X8R8G8B8, + D3DFMT_X1R5G5B5, + D3DFMT_R5G6B5, + }; + unsigned i; + + if (fmt == D3DFMT_A2R10G10B10 && win) { return FALSE; } + + for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { + if (fmt == allowed[i]) { return TRUE; } + } + return FALSE; +} + +HRESULT WINAPI +NineAdapter9_CheckDeviceFormat( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + DWORD Usage, + D3DRESOURCETYPE RType, + D3DFORMAT CheckFormat ) +{ + struct pipe_screen *screen; + HRESULT hr; + enum pipe_format pf; + enum pipe_texture_target target; + unsigned bind = 0; + + /* Check adapter format. */ + + /* Nicer output if we only have the line at the end. */ +#if 1 + DBG("This=%p DeviceType=%s AdapterFormat=%s\n", This, + nine_D3DDEVTYPE_to_str(DeviceType), d3dformat_to_string(AdapterFormat)); +#endif + user_assert(display_format(AdapterFormat, FALSE), D3DERR_INVALIDCALL); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) + return hr; + pf = d3d9_to_pipe_format(AdapterFormat); + if (pf == PIPE_FORMAT_NONE || + !screen->is_format_supported(screen, pf, PIPE_TEXTURE_2D, 0, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED)) { + DBG("AdapterFormat %s not available.\n", + d3dformat_to_string(AdapterFormat)); + return D3DERR_NOTAVAILABLE; + } + + /* Check actual format. */ + + switch (RType) { + case D3DRTYPE_SURFACE: target = PIPE_TEXTURE_2D; break; + case D3DRTYPE_TEXTURE: target = PIPE_TEXTURE_2D; break; + case D3DRTYPE_CUBETEXTURE: target = PIPE_TEXTURE_CUBE; break; + case D3DRTYPE_VOLUME: target = PIPE_TEXTURE_3D; break; + case D3DRTYPE_VOLUMETEXTURE: target = PIPE_TEXTURE_3D; break; + case D3DRTYPE_VERTEXBUFFER: target = PIPE_BUFFER; break; + case D3DRTYPE_INDEXBUFFER: target = PIPE_BUFFER; break; + default: + user_assert(0, D3DERR_INVALIDCALL); + } + + bind = 0; + if (Usage & D3DUSAGE_RENDERTARGET) bind |= PIPE_BIND_RENDER_TARGET; + if (Usage & D3DUSAGE_DEPTHSTENCIL) bind |= PIPE_BIND_DEPTH_STENCIL; + + /* API hack because setting RT[0] to NULL is forbidden */ + if (CheckFormat == D3DFMT_NULL && bind == PIPE_BIND_RENDER_TARGET && + (RType == D3DRTYPE_SURFACE || + RType == D3DRTYPE_TEXTURE)) + return D3D_OK; + + if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING) + bind |= PIPE_BIND_BLENDABLE; + + if (Usage & D3DUSAGE_DMAP) { + DBG("D3DUSAGE_DMAP not available\n"); + return D3DERR_NOTAVAILABLE; /* TODO: displacement mapping */ + } + + switch (RType) { + case D3DRTYPE_TEXTURE: bind |= PIPE_BIND_SAMPLER_VIEW; break; + case D3DRTYPE_CUBETEXTURE: bind |= PIPE_BIND_SAMPLER_VIEW; break; + case D3DRTYPE_VOLUMETEXTURE: bind |= PIPE_BIND_SAMPLER_VIEW; break; + case D3DRTYPE_VERTEXBUFFER: bind |= PIPE_BIND_VERTEX_BUFFER; break; + case D3DRTYPE_INDEXBUFFER: bind |= PIPE_BIND_INDEX_BUFFER; break; + default: + break; + } + + + pf = d3d9_to_pipe_format(CheckFormat); + if (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) + pf = util_format_srgb(pf); + + DBG("Format=%s/%s Usage/Bind=%x/%d RType/Target=%u/%s\n", // replace %d to %s + d3dformat_to_string(CheckFormat), util_format_name(pf), + Usage, bind, // temporary simplified for merge, FIXME + /* Usage, util_dump_bind_flags(bind), */ + RType, util_dump_tex_target(target, TRUE)); + + if (pf == PIPE_FORMAT_NONE || + !screen->is_format_supported(screen, pf, target, 0, bind)) { + DBG("NOT AVAILABLE\n"); + return D3DERR_NOTAVAILABLE; + } + + /* if (Usage & D3DUSAGE_NONSECURE) { don't know the implications of this } */ + /* if (Usage & D3DUSAGE_SOFTWAREPROCESSING) { we can always support this } */ + + if ((Usage & D3DUSAGE_AUTOGENMIPMAP) && !(bind & PIPE_BIND_SAMPLER_VIEW)) + return D3DOK_NOAUTOGEN; + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SurfaceFormat, + BOOL Windowed, + D3DMULTISAMPLE_TYPE MultiSampleType, + DWORD *pQualityLevels ) +{ + struct pipe_screen *screen; + HRESULT hr; + enum pipe_format pf; + unsigned bind; + + DBG("This=%p DeviceType=%s SurfaceFormat=%s Windowed=%i MultiSampleType=%u " + "pQualityLevels=%p\n", This, nine_D3DDEVTYPE_to_str(DeviceType), + d3dformat_to_string(SurfaceFormat), Windowed, MultiSampleType, + pQualityLevels); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) + return hr; + + pf = d3d9_to_pipe_format(SurfaceFormat); + bind = util_format_is_depth_or_stencil(pf) ? + PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET; + + if (pf == PIPE_FORMAT_NONE || + !screen->is_format_supported(screen, pf, PIPE_TEXTURE_2D, + MultiSampleType, bind)) { + DBG("%s with %u samples not available.\n", + d3dformat_to_string(SurfaceFormat), MultiSampleType); + return D3DERR_NOTAVAILABLE; + } + + if (pQualityLevels) + *pQualityLevels = 1; /* gallium doesn't have quality levels */ + + return D3D_OK; +} + +static INLINE boolean +depth_stencil_format( D3DFORMAT fmt ) +{ + static D3DFORMAT allowed[] = { + D3DFMT_D16_LOCKABLE, + D3DFMT_D32, + D3DFMT_D15S1, + D3DFMT_D24S8, + D3DFMT_D24X8, + D3DFMT_D24X4S4, + D3DFMT_D16, + D3DFMT_D32F_LOCKABLE, + D3DFMT_D24FS8, + D3DFMT_D32_LOCKABLE + }; + unsigned i; + + for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { + if (fmt == allowed[i]) { return TRUE; } + } + return FALSE; +} + +HRESULT WINAPI +NineAdapter9_CheckDepthStencilMatch( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + D3DFORMAT RenderTargetFormat, + D3DFORMAT DepthStencilFormat ) +{ + struct pipe_screen *screen; + enum pipe_format dfmt, bfmt, zsfmt; + HRESULT hr; + + DBG("This=%p DeviceType=%s AdapterFormat=%s " + "RenderTargetFormat=%s DepthStencilFormat=%s\n", This, + nine_D3DDEVTYPE_to_str(DeviceType), d3dformat_to_string(AdapterFormat), + d3dformat_to_string(RenderTargetFormat), + d3dformat_to_string(DepthStencilFormat)); + + user_assert(display_format(AdapterFormat, FALSE), D3DERR_NOTAVAILABLE); + user_assert(depth_stencil_format(DepthStencilFormat), D3DERR_NOTAVAILABLE); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) { return hr; } + + dfmt = d3d9_to_pipe_format(AdapterFormat); + bfmt = d3d9_to_pipe_format(RenderTargetFormat); + if (RenderTargetFormat == D3DFMT_NULL) + bfmt = dfmt; + zsfmt = d3d9_to_pipe_format(DepthStencilFormat); + if (dfmt == PIPE_FORMAT_NONE || + bfmt == PIPE_FORMAT_NONE || + zsfmt == PIPE_FORMAT_NONE) { + return D3DERR_NOTAVAILABLE; + } + + if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 0, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED) || + !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) || + !screen->is_format_supported(screen, zsfmt, PIPE_TEXTURE_2D, 0, + PIPE_BIND_DEPTH_STENCIL)) { + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_CheckDeviceFormatConversion( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SourceFormat, + D3DFORMAT TargetFormat ) +{ + /* MSDN says this tests whether a certain backbuffer format can be used in + * conjunction with a certain front buffer format. It's a little confusing + * but some one wiser might be able to figure this one out. XXX */ + struct pipe_screen *screen; + enum pipe_format dfmt, bfmt; + HRESULT hr; + + DBG("This=%p DeviceType=%s SourceFormat=%s TargetFormat=%s\n", This, + nine_D3DDEVTYPE_to_str(DeviceType), + d3dformat_to_string(SourceFormat), d3dformat_to_string(TargetFormat)); + + user_assert(backbuffer_format(TargetFormat, SourceFormat, FALSE), + D3DERR_NOTAVAILABLE); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) { return hr; } + + dfmt = d3d9_to_pipe_format(TargetFormat); + bfmt = d3d9_to_pipe_format(SourceFormat); + if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) { + return D3DERR_NOTAVAILABLE; + } + if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 1, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED) || + !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 1, + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SHARED)) { + DBG("%s to %s not supported.\n", + d3dformat_to_string(SourceFormat), + d3dformat_to_string(TargetFormat)); + return D3DERR_NOTAVAILABLE; + } + + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DCAPS9 *pCaps ) +{ + struct pipe_screen *screen; + boolean sm3, vs; + HRESULT hr; + + DBG("This=%p DeviceType=%s pCaps=%p\n", This, + nine_D3DDEVTYPE_to_str(DeviceType), pCaps); + + user_assert(pCaps, D3DERR_INVALIDCALL); + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) { + DBG("Failed to get pipe_screen.\n"); + return hr; + } + +#define D3DPIPECAP(pcap, d3dcap) \ + (screen->get_param(screen, PIPE_CAP_##pcap) ? (d3dcap) : 0) + +#define D3DNPIPECAP(pcap, d3dcap) \ + (screen->get_param(screen, PIPE_CAP_##pcap) ? 0 : (d3dcap)) + + sm3 = screen->get_param(screen, PIPE_CAP_SM3); + vs = !!(screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS)); + + pCaps->DeviceType = DeviceType; + + pCaps->AdapterOrdinal = 0; + + pCaps->Caps = 0; + + pCaps->Caps2 = D3DCAPS2_CANMANAGERESOURCE | + /* D3DCAPS2_CANSHARERESOURCE | */ + /* D3DCAPS2_CANCALIBRATEGAMMA | */ + D3DCAPS2_DYNAMICTEXTURES | + D3DCAPS2_FULLSCREENGAMMA | + D3DCAPS2_CANAUTOGENMIPMAP; + + /* Note: D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD just means the + * backbuffer can be ARGB (instead of only XRGB) when we are fullscreen + * and in discard mode. */ + pCaps->Caps3 = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD | + D3DCAPS3_COPY_TO_VIDMEM | + D3DCAPS3_COPY_TO_SYSTEMMEM | + D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION; + + pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_DEFAULT | + D3DPRESENT_INTERVAL_ONE | + D3DPRESENT_INTERVAL_TWO | + D3DPRESENT_INTERVAL_THREE | + D3DPRESENT_INTERVAL_FOUR | + D3DPRESENT_INTERVAL_IMMEDIATE; + pCaps->CursorCaps = D3DCURSORCAPS_COLOR | D3DCURSORCAPS_LOWRES; + + pCaps->DevCaps = D3DDEVCAPS_CANBLTSYSTONONLOCAL | + D3DDEVCAPS_CANRENDERAFTERFLIP | + D3DDEVCAPS_DRAWPRIMITIVES2 | + D3DDEVCAPS_DRAWPRIMITIVES2EX | + D3DDEVCAPS_DRAWPRIMTLVERTEX | + D3DDEVCAPS_EXECUTESYSTEMMEMORY | + D3DDEVCAPS_EXECUTEVIDEOMEMORY | + D3DDEVCAPS_HWRASTERIZATION | + D3DDEVCAPS_HWTRANSFORMANDLIGHT | + /*D3DDEVCAPS_NPATCHES |*/ + D3DDEVCAPS_PUREDEVICE | + /*D3DDEVCAPS_QUINTICRTPATCHES |*/ + /*D3DDEVCAPS_RTPATCHES |*/ + /*D3DDEVCAPS_RTPATCHHANDLEZERO |*/ + /*D3DDEVCAPS_SEPARATETEXTUREMEMORIES |*/ + /*D3DDEVCAPS_TEXTURENONLOCALVIDMEM |*/ + D3DDEVCAPS_TEXTURESYSTEMMEMORY | + D3DDEVCAPS_TEXTUREVIDEOMEMORY | + D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | + D3DDEVCAPS_TLVERTEXVIDEOMEMORY; + + pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_MASKZ | + D3DPMISCCAPS_CULLNONE | /* XXX */ + D3DPMISCCAPS_CULLCW | + D3DPMISCCAPS_CULLCCW | + D3DPMISCCAPS_COLORWRITEENABLE | + D3DPMISCCAPS_CLIPPLANESCALEDPOINTS | + D3DPMISCCAPS_CLIPTLVERTS | + D3DPMISCCAPS_TSSARGTEMP | + D3DPMISCCAPS_BLENDOP | + D3DPIPECAP(INDEP_BLEND_ENABLE, D3DPMISCCAPS_INDEPENDENTWRITEMASKS) | + /*D3DPMISCCAPS_PERSTAGECONSTANT |*/ + /*D3DPMISCCAPS_POSTBLENDSRGBCONVERT |*/ /* TODO */ + D3DPMISCCAPS_FOGANDSPECULARALPHA | + D3DPIPECAP(BLEND_EQUATION_SEPARATE, D3DPMISCCAPS_SEPARATEALPHABLEND) | + D3DPIPECAP(MIXED_COLORBUFFER_FORMATS, D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) | + D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING | + /*D3DPMISCCAPS_FOGVERTEXCLAMPED*/0; + + pCaps->RasterCaps = + D3DPIPECAP(ANISOTROPIC_FILTER, D3DPRASTERCAPS_ANISOTROPY) | + /*D3DPRASTERCAPS_COLORPERSPECTIVE |*/ + D3DPRASTERCAPS_DITHER | + D3DPRASTERCAPS_DEPTHBIAS | + /*D3DPRASTERCAPS_FOGRANGE |*/ + /*D3DPRASTERCAPS_FOGTABLE |*/ + /*D3DPRASTERCAPS_FOGVERTEX |*/ + D3DPRASTERCAPS_MIPMAPLODBIAS | + D3DPRASTERCAPS_MULTISAMPLE_TOGGLE | + D3DPRASTERCAPS_SCISSORTEST | + D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS | + /*D3DPRASTERCAPS_WBUFFER |*/ + /*D3DPRASTERCAPS_WFOG |*/ + /*D3DPRASTERCAPS_ZBUFFERLESSHSR |*/ + /*D3DPRASTERCAPS_ZFOG |*/ + D3DPRASTERCAPS_ZTEST; + + pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER | + D3DPCMPCAPS_LESS | + D3DPCMPCAPS_EQUAL | + D3DPCMPCAPS_LESSEQUAL | + D3DPCMPCAPS_GREATER | + D3DPCMPCAPS_NOTEQUAL | + D3DPCMPCAPS_GREATEREQUAL | + D3DPCMPCAPS_ALWAYS; + + pCaps->SrcBlendCaps = D3DPBLENDCAPS_ZERO | + D3DPBLENDCAPS_ONE | + D3DPBLENDCAPS_SRCCOLOR | + D3DPBLENDCAPS_INVSRCCOLOR | + D3DPBLENDCAPS_SRCALPHA | + D3DPBLENDCAPS_INVSRCALPHA | + D3DPBLENDCAPS_DESTALPHA | + D3DPBLENDCAPS_INVDESTALPHA | + D3DPBLENDCAPS_DESTCOLOR | + D3DPBLENDCAPS_INVDESTCOLOR | + D3DPBLENDCAPS_SRCALPHASAT | + D3DPBLENDCAPS_BOTHSRCALPHA | + D3DPBLENDCAPS_BOTHINVSRCALPHA | + D3DPBLENDCAPS_BLENDFACTOR | + D3DPIPECAP(MAX_DUAL_SOURCE_RENDER_TARGETS, + D3DPBLENDCAPS_INVSRCCOLOR2 | + D3DPBLENDCAPS_SRCCOLOR2); + + pCaps->DestBlendCaps = pCaps->SrcBlendCaps; + + pCaps->AlphaCmpCaps = D3DPCMPCAPS_LESS | + D3DPCMPCAPS_EQUAL | + D3DPCMPCAPS_LESSEQUAL | + D3DPCMPCAPS_GREATER | + D3DPCMPCAPS_NOTEQUAL | + D3DPCMPCAPS_GREATEREQUAL | + D3DPCMPCAPS_ALWAYS; + + /* FLAT caps not legal for D3D9. */ + pCaps->ShadeCaps = D3DPSHADECAPS_COLORGOURAUDRGB | + D3DPSHADECAPS_SPECULARGOURAUDRGB | + D3DPSHADECAPS_ALPHAGOURAUDBLEND | + D3DPSHADECAPS_FOGGOURAUD; + + pCaps->TextureCaps = + D3DPTEXTURECAPS_ALPHA | + D3DPTEXTURECAPS_ALPHAPALETTE | + D3DPTEXTURECAPS_PERSPECTIVE | + D3DPTEXTURECAPS_PROJECTED | + /*D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE |*/ + D3DPTEXTURECAPS_CUBEMAP | + D3DPTEXTURECAPS_VOLUMEMAP | + D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_POW2) | + D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_NONPOW2CONDITIONAL) | + D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_CUBEMAP_POW2) | + D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_VOLUMEMAP_POW2) | + D3DPIPECAP(MAX_TEXTURE_2D_LEVELS, D3DPTEXTURECAPS_MIPMAP) | + D3DPIPECAP(MAX_TEXTURE_3D_LEVELS, D3DPTEXTURECAPS_MIPVOLUMEMAP) | + D3DPIPECAP(MAX_TEXTURE_CUBE_LEVELS, D3DPTEXTURECAPS_MIPCUBEMAP); + + pCaps->TextureFilterCaps = + D3DPTFILTERCAPS_MINFPOINT | + D3DPTFILTERCAPS_MINFLINEAR | + D3DPIPECAP(ANISOTROPIC_FILTER, D3DPTFILTERCAPS_MINFANISOTROPIC) | + /*D3DPTFILTERCAPS_MINFPYRAMIDALQUAD |*/ + /*D3DPTFILTERCAPS_MINFGAUSSIANQUAD |*/ + D3DPTFILTERCAPS_MIPFPOINT | + D3DPTFILTERCAPS_MIPFLINEAR | + D3DPTFILTERCAPS_MAGFPOINT | + D3DPTFILTERCAPS_MAGFLINEAR | + D3DPIPECAP(ANISOTROPIC_FILTER, D3DPTFILTERCAPS_MAGFANISOTROPIC) | + /*D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD |*/ + /*D3DPTFILTERCAPS_MAGFGAUSSIANQUAD*/0; + + pCaps->CubeTextureFilterCaps = pCaps->TextureFilterCaps; + pCaps->VolumeTextureFilterCaps = pCaps->TextureFilterCaps; + + pCaps->TextureAddressCaps = + D3DPTADDRESSCAPS_BORDER | + D3DPTADDRESSCAPS_INDEPENDENTUV | + D3DPTADDRESSCAPS_WRAP | + D3DPTADDRESSCAPS_MIRROR | + D3DPTADDRESSCAPS_CLAMP | + D3DPIPECAP(TEXTURE_MIRROR_CLAMP, D3DPTADDRESSCAPS_MIRRORONCE); + + pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps; + + pCaps->LineCaps = + D3DLINECAPS_ALPHACMP | + D3DLINECAPS_BLEND | + D3DLINECAPS_TEXTURE | + D3DLINECAPS_ZTEST | + D3DLINECAPS_FOG; + if (screen->get_paramf(screen, PIPE_CAPF_MAX_LINE_WIDTH_AA) > 0.0) { + pCaps->LineCaps |= D3DLINECAPS_ANTIALIAS; + } + + pCaps->MaxTextureWidth = + 1 << (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + pCaps->MaxTextureHeight = pCaps->MaxTextureWidth; + pCaps->MaxVolumeExtent = + 1 << (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS) - 1); + /* XXX values from wine */ + pCaps->MaxTextureRepeat = 32768; + pCaps->MaxTextureAspectRatio = pCaps->MaxTextureWidth; + + pCaps->MaxAnisotropy = + (DWORD)screen->get_paramf(screen, PIPE_CAPF_MAX_TEXTURE_ANISOTROPY); + + pCaps->MaxVertexW = 1.0f; /* XXX */ + pCaps->GuardBandLeft = screen->get_paramf(screen, + PIPE_CAPF_GUARD_BAND_LEFT); + pCaps->GuardBandTop = screen->get_paramf(screen, + PIPE_CAPF_GUARD_BAND_TOP); + pCaps->GuardBandRight = screen->get_paramf(screen, + PIPE_CAPF_GUARD_BAND_RIGHT); + pCaps->GuardBandBottom = screen->get_paramf(screen, + PIPE_CAPF_GUARD_BAND_BOTTOM); + pCaps->ExtentsAdjust = 0.0f; + + pCaps->StencilCaps = + D3DSTENCILCAPS_KEEP | + D3DSTENCILCAPS_ZERO | + D3DSTENCILCAPS_REPLACE | + D3DSTENCILCAPS_INCRSAT | + D3DSTENCILCAPS_DECRSAT | + D3DSTENCILCAPS_INVERT | + D3DSTENCILCAPS_INCR | + D3DSTENCILCAPS_DECR | + D3DPIPECAP(TWO_SIDED_STENCIL, D3DSTENCILCAPS_TWOSIDED); + + pCaps->FVFCaps = + (D3DFVFCAPS_TEXCOORDCOUNTMASK & 0xff) | + /*D3DFVFCAPS_DONOTSTRIPELEMENTS |*/ + D3DFVFCAPS_PSIZE; + + /* XXX: Some of these are probably not in SM2.0 so cap them when I figure + * them out. For now leave them all enabled. */ + pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE | + D3DTEXOPCAPS_SELECTARG1 | + D3DTEXOPCAPS_SELECTARG2 | + D3DTEXOPCAPS_MODULATE | + D3DTEXOPCAPS_MODULATE2X | + D3DTEXOPCAPS_MODULATE4X | + D3DTEXOPCAPS_ADD | + D3DTEXOPCAPS_ADDSIGNED | + D3DTEXOPCAPS_ADDSIGNED2X | + D3DTEXOPCAPS_SUBTRACT | + D3DTEXOPCAPS_ADDSMOOTH | + D3DTEXOPCAPS_BLENDDIFFUSEALPHA | + D3DTEXOPCAPS_BLENDTEXTUREALPHA | + D3DTEXOPCAPS_BLENDFACTORALPHA | + D3DTEXOPCAPS_BLENDTEXTUREALPHAPM | + D3DTEXOPCAPS_BLENDCURRENTALPHA | + D3DTEXOPCAPS_PREMODULATE | + D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | + D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | + D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | + D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA | + D3DTEXOPCAPS_BUMPENVMAP | + D3DTEXOPCAPS_BUMPENVMAPLUMINANCE | + D3DTEXOPCAPS_DOTPRODUCT3 | + D3DTEXOPCAPS_MULTIPLYADD | + D3DTEXOPCAPS_LERP; + + pCaps->MaxTextureBlendStages = 8; /* XXX wine */ + (DWORD)screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE); + pCaps->MaxSimultaneousTextures = screen->get_shader_param(screen, + PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS); + if (pCaps->MaxSimultaneousTextures > NINE_MAX_SAMPLERS_PS) + pCaps->MaxSimultaneousTextures = NINE_MAX_SAMPLERS_PS; + + pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN | + /*D3DVTXPCAPS_TEXGEN_SPHEREMAP |*/ + D3DVTXPCAPS_MATERIALSOURCE7 | + D3DVTXPCAPS_DIRECTIONALLIGHTS | + D3DVTXPCAPS_POSITIONALLIGHTS | + D3DVTXPCAPS_LOCALVIEWER | + D3DVTXPCAPS_TWEENING | + /*D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/0; + + pCaps->MaxActiveLights = NINE_MAX_LIGHTS_ACTIVE; /* like GL_LIGHTi */ + pCaps->MaxUserClipPlanes = PIPE_MAX_CLIP_PLANES; + pCaps->MaxVertexBlendMatrices = 4; /* 1 vec4 BLENDWEIGHT/INDICES input */ + pCaps->MaxVertexBlendMatrixIndex = 7; /* D3DTS_WORLDMATRIX(0..7) */ + + pCaps->MaxPointSize = screen->get_paramf(screen, PIPE_CAPF_MAX_POINT_WIDTH); + + pCaps->MaxPrimitiveCount = 0xFFFFF; /* <- wine, really 0xFFFFFFFF; */ + pCaps->MaxVertexIndex = 0xFFFFF; /* <- wine, really 0xFFFFFFFF */ + pCaps->MaxStreams = + _min(screen->get_shader_param(screen, + PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_MAX_INPUTS), + 16); + + pCaps->MaxStreamStride = screen->get_param(screen, + PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE); + + pCaps->VertexShaderVersion = sm3 ? D3DVS_VERSION(3,0) : D3DVS_VERSION(2,0); + if (vs) { + /* VS 2 as well as 3.0 supports a minimum of 256 consts, no matter how + * much our architecture moans about it. The problem is that D3D9 + * expects access to 16 int consts (i#), containing 3 components and + * 16 booleans (b#), containing only 1 component. This should be packed + * into 20 float vectors (16 for i# and 16/4 for b#), since gallium has + * removed support for the loop counter/boolean files. */ + pCaps->MaxVertexShaderConst = + _min((screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) / + sizeof(float[4])) - 20, + NINE_MAX_CONST_F); + /* Fake the minimum cap for Windows. */ + if (QUIRK(FAKE_CAPS)) { + pCaps->MaxVertexShaderConst = 256; + } + } else { + pCaps->MaxVertexShaderConst = 0; + } + + pCaps->PixelShaderVersion = sm3 ? D3DPS_VERSION(3,0) : D3DPS_VERSION(2,0); + pCaps->PixelShader1xMaxValue = 8.0f; /* XXX: wine */ + + pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET | + D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET | + D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES | + /*D3DDEVCAPS2_DMAPNPATCH |*/ + /*D3DDEVCAPS2_ADAPTIVETESSRTPATCH |*/ + /*D3DDEVCAPS2_ADAPTIVETESSNPATCH |*/ + /*D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH*/0; + + pCaps->MasterAdapterOrdinal = 0; + pCaps->AdapterOrdinalInGroup = 0; + pCaps->NumberOfAdaptersInGroup = 1; + + /* Undocumented ? */ + pCaps->MaxNpatchTessellationLevel = 0.0f; + pCaps->Reserved5 = 0; + + /* XXX: use is_format_supported */ + pCaps->DeclTypes = D3DDTCAPS_UBYTE4 | + D3DDTCAPS_UBYTE4N | + D3DDTCAPS_SHORT2N | + D3DDTCAPS_SHORT4N | + D3DDTCAPS_USHORT2N | + D3DDTCAPS_USHORT4N | + D3DDTCAPS_UDEC3 | + D3DDTCAPS_DEC3N | + D3DDTCAPS_FLOAT16_2 | + D3DDTCAPS_FLOAT16_4; + + pCaps->NumSimultaneousRTs = + screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS); + if (pCaps->NumSimultaneousRTs > NINE_MAX_SIMULTANEOUS_RENDERTARGETS) + pCaps->NumSimultaneousRTs = NINE_MAX_SIMULTANEOUS_RENDERTARGETS; + + pCaps->StretchRectFilterCaps = D3DPTFILTERCAPS_MINFPOINT | + D3DPTFILTERCAPS_MINFLINEAR | + D3DPTFILTERCAPS_MAGFPOINT | + D3DPTFILTERCAPS_MAGFLINEAR; + + + pCaps->VS20Caps.Caps = D3DVS20CAPS_PREDICATION; + pCaps->VS20Caps.DynamicFlowControlDepth = /* XXX is this dynamic ? */ + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + pCaps->VS20Caps.NumTemps = + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_TEMPS); + pCaps->VS20Caps.StaticFlowControlDepth = /* XXX is this static ? */ + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + + /* also check for values < 0, because get_shader_param may return unsigned */ + if (pCaps->VS20Caps.DynamicFlowControlDepth > D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH + || pCaps->VS20Caps.DynamicFlowControlDepth < 0) + pCaps->VS20Caps.DynamicFlowControlDepth = D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH; + if (pCaps->VS20Caps.StaticFlowControlDepth > D3DVS20_MAX_STATICFLOWCONTROLDEPTH + || pCaps->VS20Caps.StaticFlowControlDepth < 0) + pCaps->VS20Caps.StaticFlowControlDepth = D3DVS20_MAX_STATICFLOWCONTROLDEPTH; + if (pCaps->VS20Caps.NumTemps > D3DVS20_MAX_NUMTEMPS) + pCaps->VS20Caps.NumTemps = D3DVS20_MAX_NUMTEMPS; + assert(pCaps->VS20Caps.DynamicFlowControlDepth >= D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH); + assert(pCaps->VS20Caps.StaticFlowControlDepth >= D3DVS20_MIN_STATICFLOWCONTROLDEPTH); + assert(pCaps->VS20Caps.NumTemps >= D3DVS20_MIN_NUMTEMPS); + + + pCaps->PS20Caps.Caps = D3DPS20CAPS_ARBITRARYSWIZZLE | + D3DPS20CAPS_GRADIENTINSTRUCTIONS | + D3DPS20CAPS_PREDICATION; + if (screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS) == + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS)) + pCaps->PS20Caps.Caps |= D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT; + if (screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS) == + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS)) + pCaps->PS20Caps.Caps |= D3DPS20CAPS_NODEPENDENTREADLIMIT; + pCaps->PS20Caps.DynamicFlowControlDepth = /* XXX is this dynamic ? */ + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + pCaps->PS20Caps.NumTemps = + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_TEMPS); + pCaps->PS20Caps.StaticFlowControlDepth = /* XXX is this static ? */ + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + pCaps->PS20Caps.NumInstructionSlots = + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS); + + if (pCaps->PS20Caps.DynamicFlowControlDepth > D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH + || pCaps->PS20Caps.DynamicFlowControlDepth < 0) + pCaps->PS20Caps.DynamicFlowControlDepth = D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH; + if (pCaps->PS20Caps.StaticFlowControlDepth > D3DPS20_MAX_STATICFLOWCONTROLDEPTH + || pCaps->PS20Caps.StaticFlowControlDepth < 0) + pCaps->PS20Caps.StaticFlowControlDepth = D3DPS20_MAX_STATICFLOWCONTROLDEPTH; + if (pCaps->PS20Caps.NumTemps > D3DPS20_MAX_NUMTEMPS) + pCaps->PS20Caps.NumTemps = D3DPS20_MAX_NUMTEMPS; + if (pCaps->PS20Caps.NumInstructionSlots > D3DPS20_MAX_NUMINSTRUCTIONSLOTS) + pCaps->PS20Caps.NumInstructionSlots = D3DPS20_MAX_NUMINSTRUCTIONSLOTS; + assert(pCaps->PS20Caps.DynamicFlowControlDepth >= D3DPS20_MIN_DYNAMICFLOWCONTROLDEPTH); + assert(pCaps->PS20Caps.StaticFlowControlDepth >= D3DPS20_MIN_STATICFLOWCONTROLDEPTH); + assert(pCaps->PS20Caps.NumTemps >= D3DPS20_MIN_NUMTEMPS); + assert(pCaps->PS20Caps.NumInstructionSlots >= D3DPS20_MIN_NUMINSTRUCTIONSLOTS); + + + if (screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS)) + pCaps->VertexTextureFilterCaps = pCaps->TextureFilterCaps & + ~(D3DPTFILTERCAPS_MIPFPOINT | + D3DPTFILTERCAPS_MIPFPOINT); /* XXX */ + else + pCaps->VertexTextureFilterCaps = 0; + + if (sm3) { + pCaps->MaxVertexShader30InstructionSlots = + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS); + pCaps->MaxPixelShader30InstructionSlots = + screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS); + if (pCaps->MaxVertexShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS) + pCaps->MaxVertexShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS; + if (pCaps->MaxPixelShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS) + pCaps->MaxPixelShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS; + assert(pCaps->MaxVertexShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS); + assert(pCaps->MaxPixelShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS); + } else { + pCaps->MaxVertexShader30InstructionSlots = 0; + pCaps->MaxPixelShader30InstructionSlots = 0; + } + + /* 65535 is required, advertise more for GPUs with >= 2048 instruction slots */ + pCaps->MaxVShaderInstructionsExecuted = MAX2(65535, pCaps->MaxVertexShader30InstructionSlots * 32); + pCaps->MaxPShaderInstructionsExecuted = MAX2(65535, pCaps->MaxPixelShader30InstructionSlots * 32); + + if (debug_get_bool_option("NINE_DUMP_CAPS", FALSE)) + nine_dump_D3DCAPS9(DBG_CHANNEL, pCaps); + + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_CreateDevice( struct NineAdapter9 *This, + UINT RealAdapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + IDirect3DDevice9 **ppReturnedDeviceInterface ) +{ + struct pipe_screen *screen; + D3DDEVICE_CREATION_PARAMETERS params; + D3DCAPS9 caps; + int major, minor; + HRESULT hr; + + DBG("This=%p RealAdapter=%u DeviceType=%s hFocusWindow=%p " + "BehaviourFlags=%x " "pD3D9=%p pPresentationGroup=%p " + "ppReturnedDeviceInterface=%p\n", This, + RealAdapter, nine_D3DDEVTYPE_to_str(DeviceType), hFocusWindow, + BehaviorFlags, pD3D9, pPresentationGroup, ppReturnedDeviceInterface); + + ID3DPresentGroup_GetVersion(pPresentationGroup, &major, &minor); + if (major != 1) { + ERR("Doesn't support the ID3DPresentGroup version %d %d. Expected 1\n", + major, minor); + return D3DERR_NOTAVAILABLE; + } + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) { + DBG("Failed to get pipe_screen.\n"); + return hr; + } + + hr = NineAdapter9_GetDeviceCaps(This, DeviceType, &caps); + if (FAILED(hr)) { + DBG("Failed to get device caps.\n"); + return hr; + } + + params.AdapterOrdinal = RealAdapter; + params.DeviceType = DeviceType; + params.hFocusWindow = hFocusWindow; + params.BehaviorFlags = BehaviorFlags; + + hr = NineDevice9_new(screen, ¶ms, &caps, pPresentationParameters, + pD3D9, pPresentationGroup, This->ctx, + (struct NineDevice9 **)ppReturnedDeviceInterface); + if (FAILED(hr)) { + DBG("Failed to create device.\n"); + return hr; + } + DBG("NineDevice9 created successfully.\n"); + + return D3D_OK; +} + +HRESULT WINAPI +NineAdapter9_CreateDeviceEx( struct NineAdapter9 *This, + UINT RealAdapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + IDirect3D9Ex *pD3D9Ex, + ID3DPresentGroup *pPresentationGroup, + IDirect3DDevice9Ex **ppReturnedDeviceInterface ) +{ + struct pipe_screen *screen; + D3DDEVICE_CREATION_PARAMETERS params; + D3DCAPS9 caps; + int major, minor; + HRESULT hr; + + DBG("This=%p RealAdapter=%u DeviceType=%s hFocusWindow=%p " + "BehaviourFlags=%x " "pD3D9Ex=%p pPresentationGroup=%p " + "ppReturnedDeviceInterface=%p\n", This, + RealAdapter, nine_D3DDEVTYPE_to_str(DeviceType), hFocusWindow, + BehaviorFlags, pD3D9Ex, pPresentationGroup, ppReturnedDeviceInterface); + + ID3DPresentGroup_GetVersion(pPresentationGroup, &major, &minor); + if (major != 1) { + ERR("Doesn't support the ID3DPresentGroup version %d %d. Expected 1\n", + major, minor); + return D3DERR_NOTAVAILABLE; + } + + hr = NineAdapter9_GetScreen(This, DeviceType, &screen); + if (FAILED(hr)) { + DBG("Failed to get pipe_screen.\n"); + return hr; + } + + hr = NineAdapter9_GetDeviceCaps(This, DeviceType, &caps); + if (FAILED(hr)) { + DBG("Failed to get device caps.\n"); + return hr; + } + + params.AdapterOrdinal = RealAdapter; + params.DeviceType = DeviceType; + params.hFocusWindow = hFocusWindow; + params.BehaviorFlags = BehaviorFlags; + + hr = NineDevice9Ex_new(screen, ¶ms, &caps, pPresentationParameters, + pFullscreenDisplayMode, + pD3D9Ex, pPresentationGroup, This->ctx, + (struct NineDevice9Ex **)ppReturnedDeviceInterface); + if (FAILED(hr)) { + DBG("Failed to create device.\n"); + return hr; + } + DBG("NineDevice9Ex created successfully.\n"); + + return D3D_OK; +} + +ID3DAdapter9Vtbl NineAdapter9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineAdapter9_GetAdapterIdentifier, + (void *)NineAdapter9_CheckDeviceType, + (void *)NineAdapter9_CheckDeviceFormat, + (void *)NineAdapter9_CheckDeviceMultiSampleType, + (void *)NineAdapter9_CheckDepthStencilMatch, + (void *)NineAdapter9_CheckDeviceFormatConversion, + (void *)NineAdapter9_GetDeviceCaps, + (void *)NineAdapter9_CreateDevice, + (void *)NineAdapter9_CreateDeviceEx +}; + +static const GUID *NineAdapter9_IIDs[] = { + &IID_ID3D9Adapter, + &IID_IUnknown, + NULL +}; + +HRESULT +NineAdapter9_new( struct d3dadapter9_context *pCTX, + struct NineAdapter9 **ppOut ) +{ + NINE_NEW(Adapter9, ppOut, FALSE, /* args */ pCTX); +} diff --git a/src/gallium/state_trackers/nine/adapter9.h b/src/gallium/state_trackers/nine/adapter9.h new file mode 100644 index 00000000000..c743347b6af --- /dev/null +++ b/src/gallium/state_trackers/nine/adapter9.h @@ -0,0 +1,137 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_ADAPTER9_H_ +#define _NINE_ADAPTER9_H_ + +#include "iunknown.h" + +#include "d3dadapter/d3dadapter9.h" + +struct pipe_screen; +struct pipe_resource; + +struct d3dadapter9_context +{ + struct pipe_screen *hal, *ref; + D3DADAPTER_IDENTIFIER9 identifier; + BOOL linear_framebuffer; + BOOL throttling; + int throttling_value; + + void (*destroy)( struct d3dadapter9_context *ctx ); +}; + +struct NineAdapter9 +{ + struct NineUnknown base; + + struct d3dadapter9_context *ctx; +}; +static INLINE struct NineAdapter9 * +NineAdapter9( void *data ) +{ + return (struct NineAdapter9 *)data; +} + +HRESULT +NineAdapter9_new( struct d3dadapter9_context *pCTX, + struct NineAdapter9 **ppOut ); + +HRESULT +NineAdapter9_ctor( struct NineAdapter9 *This, + struct NineUnknownParams *pParams, + struct d3dadapter9_context *pCTX ); + +void +NineAdapter9_dtor( struct NineAdapter9 *This ); + +HRESULT WINAPI +NineAdapter9_GetAdapterIdentifier( struct NineAdapter9 *This, + DWORD Flags, + D3DADAPTER_IDENTIFIER9 *pIdentifier ); + +HRESULT WINAPI +NineAdapter9_CheckDeviceType( struct NineAdapter9 *This, + D3DDEVTYPE DevType, + D3DFORMAT AdapterFormat, + D3DFORMAT BackBufferFormat, + BOOL bWindowed ); + +HRESULT WINAPI +NineAdapter9_CheckDeviceFormat( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + DWORD Usage, + D3DRESOURCETYPE RType, + D3DFORMAT CheckFormat ); + +HRESULT WINAPI +NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SurfaceFormat, + BOOL Windowed, + D3DMULTISAMPLE_TYPE MultiSampleType, + DWORD *pQualityLevels ); + +HRESULT WINAPI +NineAdapter9_CheckDepthStencilMatch( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT AdapterFormat, + D3DFORMAT RenderTargetFormat, + D3DFORMAT DepthStencilFormat ); + +HRESULT WINAPI +NineAdapter9_CheckDeviceFormatConversion( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DFORMAT SourceFormat, + D3DFORMAT TargetFormat ); + +HRESULT WINAPI +NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, + D3DDEVTYPE DeviceType, + D3DCAPS9 *pCaps ); + +HRESULT WINAPI +NineAdapter9_CreateDevice( struct NineAdapter9 *This, + UINT RealAdapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + IDirect3DDevice9 **ppReturnedDeviceInterface ); + +HRESULT WINAPI +NineAdapter9_CreateDeviceEx( struct NineAdapter9 *This, + UINT RealAdapter, + D3DDEVTYPE DeviceType, + HWND hFocusWindow, + DWORD BehaviorFlags, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + IDirect3D9Ex *pD3D9Ex, + ID3DPresentGroup *pPresentationGroup, + IDirect3DDevice9Ex **ppReturnedDeviceInterface ); + +#endif /* _NINE_ADAPTER9_H_ */ diff --git a/src/gallium/state_trackers/nine/authenticatedchannel9.c b/src/gallium/state_trackers/nine/authenticatedchannel9.c new file mode 100644 index 00000000000..44ad87c956f --- /dev/null +++ b/src/gallium/state_trackers/nine/authenticatedchannel9.c @@ -0,0 +1,78 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "authenticatedchannel9.h" + +#define DBG_CHANNEL DBG_AUTHENTICATEDCHANNEL + +HRESULT WINAPI +NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput ) +{ + STUB(D3DERR_INVALIDCALL); +} + +IDirect3DAuthenticatedChannel9Vtbl NineAuthenticatedChannel9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineAuthenticatedChannel9_GetCertificateSize, + (void *)NineAuthenticatedChannel9_GetCertificate, + (void *)NineAuthenticatedChannel9_NegotiateKeyExchange, + (void *)NineAuthenticatedChannel9_Query, + (void *)NineAuthenticatedChannel9_Configure +}; diff --git a/src/gallium/state_trackers/nine/authenticatedchannel9.h b/src/gallium/state_trackers/nine/authenticatedchannel9.h new file mode 100644 index 00000000000..7d374f67fca --- /dev/null +++ b/src/gallium/state_trackers/nine/authenticatedchannel9.h @@ -0,0 +1,65 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_AUTHENTICATEDCHANNEL9_H_ +#define _NINE_AUTHENTICATEDCHANNEL9_H_ + +#include "iunknown.h" + +struct NineAuthenticatedChannel9 +{ + struct NineUnknown base; +}; +static INLINE struct NineAuthenticatedChannel9 * +NineAuthenticatedChannel9( void *data ) +{ + return (struct NineAuthenticatedChannel9 *)data; +} + +HRESULT WINAPI +NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ); + +HRESULT WINAPI +NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ); + +HRESULT WINAPI +NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ); + +HRESULT WINAPI +NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ); + +HRESULT WINAPI +NineAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput ); + +#endif /* _NINE_AUTHENTICATEDCHANNEL9_H_ */ diff --git a/src/gallium/state_trackers/nine/basetexture9.c b/src/gallium/state_trackers/nine/basetexture9.c new file mode 100644 index 00000000000..89f6269a742 --- /dev/null +++ b/src/gallium/state_trackers/nine/basetexture9.c @@ -0,0 +1,504 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "basetexture9.h" +#include "device9.h" + +/* For UploadSelf: */ +#include "texture9.h" +#include "cubetexture9.h" +#include "volumetexture9.h" + +#ifdef DEBUG +#include "nine_pipe.h" +#include "nine_dump.h" +#endif + +#include "util/u_format.h" +#include "util/u_gen_mipmap.h" + +#define DBG_CHANNEL DBG_BASETEXTURE + +HRESULT +NineBaseTexture9_ctor( struct NineBaseTexture9 *This, + struct NineUnknownParams *pParams, + D3DRESOURCETYPE Type, + D3DPOOL Pool ) +{ + BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !This->base.resource && + (This->format != D3DFMT_NULL); + HRESULT hr; + DWORD usage = This->base.usage; + + user_assert(!(usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) || + Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(!(usage & D3DUSAGE_DYNAMIC) || + Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL); + + hr = NineResource9_ctor(&This->base, pParams, alloc, Type, Pool); + if (FAILED(hr)) + return hr; + + This->pipe = pParams->device->pipe; + This->mipfilter = (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? + D3DTEXF_LINEAR : D3DTEXF_NONE; + This->lod = 0; + This->lod_resident = -1; + This->shadow = This->format != D3DFMT_INTZ && util_format_has_depth( + util_format_description(This->base.info.format)); + + list_inithead(&This->list); + + return D3D_OK; +} + +void +NineBaseTexture9_dtor( struct NineBaseTexture9 *This ) +{ + DBG("This=%p\n", This); + + pipe_sampler_view_reference(&This->view[0], NULL); + pipe_sampler_view_reference(&This->view[1], NULL); + + list_del(&This->list), + + NineResource9_dtor(&This->base); +} + +DWORD WINAPI +NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ) +{ + DWORD old = This->lod; + + user_assert(This->base.pool == D3DPOOL_MANAGED, 0); + + This->lod = MIN2(LODNew, This->base.info.last_level); + + if (This->lod != old && This->bind_count && LIST_IS_EMPTY(&This->list)) + list_add(&This->list, &This->base.base.device->update_textures); + + return old; +} + +DWORD WINAPI +NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This ) +{ + return This->lod; +} + +DWORD WINAPI +NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ) +{ + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + return 1; + return This->base.info.last_level + 1; +} + +HRESULT WINAPI +NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ) +{ + if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP)) + return D3D_OK; + user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL); + + This->mipfilter = FilterType; + + return D3D_OK; +} + +D3DTEXTUREFILTERTYPE WINAPI +NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ) +{ + return This->mipfilter; +} + +HRESULT +NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) +{ + HRESULT hr; + unsigned last_level = This->base.info.last_level; + unsigned l; + + DBG("This=%p dirty=%i type=%s\n", This, This->dirty, + nine_D3DRTYPE_to_str(This->base.type)); + + assert(This->base.pool == D3DPOOL_MANAGED); + + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + last_level = 0; /* TODO: What if level 0 is not resident ? */ + + if (This->lod_resident != This->lod) { + struct pipe_resource *res; + + DBG("updating LOD from %u to %u ...\n", This->lod_resident, This->lod); + + pipe_sampler_view_reference(&This->view[0], NULL); + pipe_sampler_view_reference(&This->view[1], NULL); + + if (This->bind_count) { + /* mark state dirty */ + struct nine_state *state = &This->base.base.device->state; + unsigned s; + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) + if (state->texture[s] == This) + state->changed.texture |= 1 << s; + if (state->changed.texture) + state->changed.group |= NINE_STATE_TEXTURE; + } + + hr = NineBaseTexture9_CreatePipeResource(This, This->lod_resident != -1); + if (FAILED(hr)) + return hr; + res = This->base.resource; + + if (This->lod_resident == -1) /* no levels were resident */ + This->lod_resident = This->base.info.last_level + 1; + + if (This->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = NineTexture9(This); + struct pipe_box box; + + /* Mark uninitialized levels as dirty. */ + box.x = box.y = box.z = 0; + box.depth = 1; + for (l = This->lod; l < This->lod_resident; ++l) { + box.width = u_minify(This->base.info.width0, l); + box.height = u_minify(This->base.info.height0, l); + NineSurface9_AddDirtyRect(tex->surfaces[l], &box); + } + for (l = 0; l < This->lod; ++l) + NineSurface9_SetResource(tex->surfaces[l], NULL, -1); + for (; l <= This->base.info.last_level; ++l) + NineSurface9_SetResource(tex->surfaces[l], res, l - This->lod); + } else + if (This->base.type == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *tex = NineCubeTexture9(This); + struct pipe_box box; + unsigned z; + + /* Mark uninitialized levels as dirty. */ + box.x = box.y = box.z = 0; + box.depth = 1; + for (l = This->lod; l < This->lod_resident; ++l) { + box.width = u_minify(This->base.info.width0, l); + box.height = u_minify(This->base.info.height0, l); + for (z = 0; z < 6; ++z) + NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box); + } + for (l = 0; l < This->lod; ++l) { + for (z = 0; z < 6; ++z) + NineSurface9_SetResource(tex->surfaces[l * 6 + z], + NULL, -1); + } + for (; l <= This->base.info.last_level; ++l) { + for (z = 0; z < 6; ++z) + NineSurface9_SetResource(tex->surfaces[l * 6 + z], + res, l - This->lod); + } + } else + if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); + struct pipe_box box; + + /* Mark uninitialized levels as dirty. */ + box.x = box.y = box.z = 0; + for (l = This->lod; l < This->lod_resident; ++l) { + box.width = u_minify(This->base.info.width0, l); + box.height = u_minify(This->base.info.height0, l); + box.depth = u_minify(This->base.info.depth0, l); + NineVolume9_AddDirtyRegion(tex->volumes[l], &box); + } + for (l = 0; l < This->lod; ++l) + NineVolume9_SetResource(tex->volumes[l], NULL, -1); + for (; l <= This->base.info.last_level; ++l) + NineVolume9_SetResource(tex->volumes[l], res, l - This->lod); + } else { + assert(!"invalid texture type"); + } + + if (This->lod < This->lod_resident) + This->dirty = TRUE; + This->lod_resident = This->lod; + } + if (!This->dirty) + return D3D_OK; + + if (This->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *tex = NineTexture9(This); + struct pipe_box box; + box.z = 0; + box.depth = 1; + + DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n", + tex->dirty_rect.x, tex->dirty_rect.y, + tex->dirty_rect.width, tex->dirty_rect.height); + + if (tex->dirty_rect.width) { + for (l = 0; l <= last_level; ++l) { + u_box_minify_2d(&box, &tex->dirty_rect, l); + NineSurface9_AddDirtyRect(tex->surfaces[l], &box); + } + memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect)); + tex->dirty_rect.depth = 1; + } + for (l = This->lod; l <= last_level; ++l) + NineSurface9_UploadSelf(tex->surfaces[l]); + } else + if (This->base.type == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *tex = NineCubeTexture9(This); + unsigned z; + struct pipe_box box; + box.z = 0; + box.depth = 1; + + for (z = 0; z < 6; ++z) { + DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z, + tex->dirty_rect[z].x, tex->dirty_rect[z].y, + tex->dirty_rect[z].width, tex->dirty_rect[z].height); + + if (tex->dirty_rect[z].width) { + for (l = 0; l <= last_level; ++l) { + u_box_minify_2d(&box, &tex->dirty_rect[z], l); + NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box); + } + memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z])); + tex->dirty_rect[z].depth = 1; + } + for (l = This->lod; l <= last_level; ++l) + NineSurface9_UploadSelf(tex->surfaces[l * 6 + z]); + } + } else + if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); + struct pipe_box box; + + DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n", + tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y, + tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth); + + if (tex->dirty_box.width) { + for (l = 0; l <= last_level; ++l) { + u_box_minify_2d(&box, &tex->dirty_box, l); + NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box); + } + memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); + } + for (l = This->lod; l <= last_level; ++l) + NineVolume9_UploadSelf(tex->volumes[l]); + } else { + assert(!"invalid texture type"); + } + This->dirty = FALSE; + + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + This->dirty_mip = TRUE; + /* TODO: if dirty only because of lod change, only generate added levels */ + + DBG("DONE, generate mip maps = %i\n", This->dirty_mip); + return D3D_OK; +} + +void WINAPI +NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) +{ + struct pipe_resource *resource = This->base.resource; + + unsigned base_level = 0; + unsigned last_level = This->base.info.last_level - This->lod; + unsigned first_layer = 0; + unsigned last_layer; + unsigned filter = This->mipfilter == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST + : PIPE_TEX_FILTER_LINEAR; + DBG("This=%p\n", This); + + if (This->base.pool == D3DPOOL_MANAGED) + NineBaseTexture9_UploadSelf(This); + if (!This->dirty_mip) + return; + if (This->lod) { + ERR("AUTOGENMIPMAP if level 0 is not resident not supported yet !\n"); + return; + } + + if (!This->view[0]) + NineBaseTexture9_UpdateSamplerView(This, 0); + + last_layer = util_max_layer(This->view[0]->texture, base_level); + + util_gen_mipmap(This->pipe, resource, + resource->format, base_level, last_level, + first_layer, last_layer, filter); + + This->dirty_mip = FALSE; + + NineDevice9_RestoreNonCSOState(This->base.base.device, ~0x3); +} + +HRESULT +NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This, + BOOL CopyData ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_screen *screen = This->base.info.screen; + struct pipe_resource templ; + unsigned l, m; + struct pipe_resource *res; + struct pipe_resource *old = This->base.resource; + + DBG("This=%p lod=%u last_level=%u\n", This, + This->lod, This->base.info.last_level); + + assert(This->base.pool == D3DPOOL_MANAGED); + + templ = This->base.info; + + if (This->lod) { + templ.width0 = u_minify(templ.width0, This->lod); + templ.height0 = u_minify(templ.height0, This->lod); + templ.depth0 = u_minify(templ.depth0, This->lod); + } + templ.last_level = This->base.info.last_level - This->lod; + + if (old) { + /* LOD might have changed. */ + if (old->width0 == templ.width0 && + old->height0 == templ.height0 && + old->depth0 == templ.depth0) + return D3D_OK; + } + + res = screen->resource_create(screen, &templ); + if (!res) + return D3DERR_OUTOFVIDEOMEMORY; + This->base.resource = res; + + if (old && CopyData) { /* Don't return without releasing old ! */ + struct pipe_box box; + box.x = 0; + box.y = 0; + box.z = 0; + + l = (This->lod < This->lod_resident) ? This->lod_resident - This->lod : 0; + m = (This->lod < This->lod_resident) ? 0 : This->lod - This->lod_resident; + + box.width = u_minify(templ.width0, l); + box.height = u_minify(templ.height0, l); + box.depth = u_minify(templ.depth0, l); + + for (; l <= templ.last_level; ++l, ++m) { + pipe->resource_copy_region(pipe, + res, l, 0, 0, 0, + old, m, &box); + box.width = u_minify(box.width, 1); + box.height = u_minify(box.height, 1); + box.depth = u_minify(box.depth, 1); + } + } + pipe_resource_reference(&old, NULL); + + return D3D_OK; +} + +HRESULT +NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This, + const int sRGB ) +{ + const struct util_format_description *desc; + struct pipe_context *pipe = This->pipe; + struct pipe_resource *resource = This->base.resource; + struct pipe_sampler_view templ; + uint8_t swizzle[4]; + + if (unlikely(!resource)) { + if (unlikely(This->format == D3DFMT_NULL)) + return D3D_OK; + NineBaseTexture9_Dump(This); + } + assert(resource); + + pipe_sampler_view_reference(&This->view[sRGB], NULL); + + swizzle[0] = PIPE_SWIZZLE_RED; + swizzle[1] = PIPE_SWIZZLE_GREEN; + swizzle[2] = PIPE_SWIZZLE_BLUE; + swizzle[3] = PIPE_SWIZZLE_ALPHA; + desc = util_format_description(resource->format); + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { + /* ZZZ1 -> 0Z01 (see end of docs/source/tgsi.rst) + * XXX: but it's wrong + swizzle[0] = PIPE_SWIZZLE_ZERO; + swizzle[2] = PIPE_SWIZZLE_ZERO; */ + } else + if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && + desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) { + /* R001/RG01 -> R111/RG11 */ + if (desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0) + swizzle[1] = PIPE_SWIZZLE_ONE; + if (desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0) + swizzle[2] = PIPE_SWIZZLE_ONE; + } + /* but 000A remains unchanged */ + + templ.format = sRGB ? util_format_srgb(resource->format) : resource->format; + templ.u.tex.first_layer = 0; + templ.u.tex.last_layer = (resource->target == PIPE_TEXTURE_CUBE) ? + 5 : (This->base.info.depth0 - 1); + templ.u.tex.first_level = 0; + templ.u.tex.last_level = resource->last_level; + templ.swizzle_r = swizzle[0]; + templ.swizzle_g = swizzle[1]; + templ.swizzle_b = swizzle[2]; + templ.swizzle_a = swizzle[3]; + templ.target = resource->target; + + This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ); + + DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource); + + return This->view ? D3D_OK : D3DERR_DRIVERINTERNALERROR; +} + +void WINAPI +NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) +{ + if (This->dirty && This->base.pool == D3DPOOL_MANAGED) + NineBaseTexture9_UploadSelf(This); +} + +#ifdef DEBUG +void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) +{ + DBG("\nNineBaseTexture9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n" + "Format=%s Dims=%ux%ux%u/%u LastLevel=%u Lod=%u(%u)\n", This, + This->base.resource, This->base.data, + nine_D3DPOOL_to_str(This->base.pool), + nine_D3DRTYPE_to_str(This->base.type), + nine_D3DUSAGE_to_str(This->base.usage), + d3dformat_to_string(This->format), + This->base.info.width0, This->base.info.height0, This->base.info.depth0, + This->base.info.array_size, This->base.info.last_level, + This->lod, This->lod_resident); +} +#endif /* DEBUG */ diff --git a/src/gallium/state_trackers/nine/basetexture9.h b/src/gallium/state_trackers/nine/basetexture9.h new file mode 100644 index 00000000000..d615376f09b --- /dev/null +++ b/src/gallium/state_trackers/nine/basetexture9.h @@ -0,0 +1,138 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_BASETEXTURE9_H_ +#define _NINE_BASETEXTURE9_H_ + +#include "resource9.h" +#include "util/u_inlines.h" +#include "util/u_double_list.h" + +struct NineBaseTexture9 +{ + struct NineResource9 base; + struct list_head list; + + /* g3d */ + struct pipe_context *pipe; + struct pipe_sampler_view *view[2]; /* linear and sRGB */ + + D3DFORMAT format; + + D3DTEXTUREFILTERTYPE mipfilter; + DWORD lod; + DWORD lod_resident; + + int16_t bind_count; /* to Device9->state.texture */ + + boolean shadow; + uint8_t pstype; /* 0: 2D, 1: 1D, 2: CUBE, 3: 3D */ + + boolean dirty; + boolean dirty_mip; +}; +static INLINE struct NineBaseTexture9 * +NineBaseTexture9( void *data ) +{ + return (struct NineBaseTexture9 *)data; +} + +HRESULT +NineBaseTexture9_ctor( struct NineBaseTexture9 *This, + struct NineUnknownParams *pParams, + D3DRESOURCETYPE Type, + D3DPOOL Pool ); + +void +NineBaseTexture9_dtor( struct NineBaseTexture9 *This ); + +DWORD WINAPI +NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ); + +DWORD WINAPI +NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This ); + +DWORD WINAPI +NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ); + +HRESULT WINAPI +NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ); + +D3DTEXTUREFILTERTYPE WINAPI +NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ); + +void WINAPI +NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ); + +void WINAPI +NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ); + +/* For D3DPOOL_MANAGED only (after SetLOD change): */ +HRESULT +NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This, + BOOL CopyData ); + +/* For D3DPOOL_MANAGED only: */ +HRESULT +NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ); + +HRESULT +NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This, + const int sRGB ); + +static INLINE void +NineBaseTexture9_Validate( struct NineBaseTexture9 *This ) +{ + DBG_FLAG(DBG_BASETEXTURE, "This=%p dirty=%i dirty_mip=%i lod=%u/%u\n", + This, This->dirty, This->dirty_mip, This->lod, This->lod_resident); + if ((This->base.pool == D3DPOOL_MANAGED) && + (This->dirty || This->lod != This->lod_resident)) + NineBaseTexture9_UploadSelf(This); + if (This->dirty_mip) + NineBaseTexture9_GenerateMipSubLevels(This); +} + +static INLINE struct pipe_sampler_view * +NineBaseTexture9_GetSamplerView( struct NineBaseTexture9 *This, const int sRGB ) +{ + if (!This->view[sRGB]) + NineBaseTexture9_UpdateSamplerView(This, sRGB); + return This->view[sRGB]; +} + +#ifdef DEBUG +void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ); +#else +static INLINE void +NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) { } +#endif + +#define BASETEX_REGISTER_UPDATE(t) do { \ + if (((t)->dirty | ((t)->dirty_mip)) && (t)->base.base.bind) \ + if (LIST_IS_EMPTY(&(t)->list)) \ + list_add(&(t)->list, &(t)->base.base.device->update_textures); \ + } while(0) + +#endif /* _NINE_BASETEXTURE9_H_ */ diff --git a/src/gallium/state_trackers/nine/cryptosession9.c b/src/gallium/state_trackers/nine/cryptosession9.c new file mode 100644 index 00000000000..2622f2b32e4 --- /dev/null +++ b/src/gallium/state_trackers/nine/cryptosession9.c @@ -0,0 +1,115 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "cryptosession9.h" + +#define DBG_CHANNEL DBG_CRYPTOSESSION + +HRESULT WINAPI +NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This, + void *pReadbackKey, + UINT KeySize ) +{ + STUB(D3DERR_INVALIDCALL); +} + +IDirect3DCryptoSession9Vtbl NineCryptoSession9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineCryptoSession9_GetCertificateSize, + (void *)NineCryptoSession9_GetCertificate, + (void *)NineCryptoSession9_NegotiateKeyExchange, + (void *)NineCryptoSession9_EncryptionBlt, + (void *)NineCryptoSession9_DecryptionBlt, + (void *)NineCryptoSession9_GetSurfacePitch, + (void *)NineCryptoSession9_StartSessionKeyRefresh, + (void *)NineCryptoSession9_FinishSessionKeyRefresh, + (void *)NineCryptoSession9_GetEncryptionBltKey +}; diff --git a/src/gallium/state_trackers/nine/cryptosession9.h b/src/gallium/state_trackers/nine/cryptosession9.h new file mode 100644 index 00000000000..660d246bfa0 --- /dev/null +++ b/src/gallium/state_trackers/nine/cryptosession9.h @@ -0,0 +1,86 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_CRYPTOSESSION9_H_ +#define _NINE_CRYPTOSESSION9_H_ + +#include "iunknown.h" + +struct NineCryptoSession9 +{ + struct NineUnknown base; +}; +static INLINE struct NineCryptoSession9 * +NineCryptoSession9( void *data ) +{ + return (struct NineCryptoSession9 *)data; +} + +HRESULT WINAPI +NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ); + +HRESULT WINAPI +NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ); + +HRESULT WINAPI +NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ); + +HRESULT WINAPI +NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ); + +HRESULT WINAPI +NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ); + +HRESULT WINAPI +NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ); + +HRESULT WINAPI +NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ); + +HRESULT WINAPI +NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ); + +HRESULT WINAPI +NineCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This, + void *pReadbackKey, + UINT KeySize ); + +#endif /* _NINE_CRYPTOSESSION9_H_ */ diff --git a/src/gallium/state_trackers/nine/cubetexture9.c b/src/gallium/state_trackers/nine/cubetexture9.c new file mode 100644 index 00000000000..77802e70220 --- /dev/null +++ b/src/gallium/state_trackers/nine/cubetexture9.c @@ -0,0 +1,274 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "cubetexture9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" + +#define DBG_CHANNEL DBG_CUBETEXTURE + + +static HRESULT +NineCubeTexture9_ctor( struct NineCubeTexture9 *This, + struct NineUnknownParams *pParams, + UINT EdgeLength, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + HANDLE *pSharedHandle ) +{ + struct pipe_resource *info = &This->base.base.info; + unsigned i; + D3DSURFACE_DESC sfdesc; + HRESULT hr; + + user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || + (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); + + user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ + + if (Usage & D3DUSAGE_AUTOGENMIPMAP) + Levels = 0; + + This->base.format = Format; + This->base.base.usage = Usage; + + info->screen = pParams->device->screen; + info->target = PIPE_TEXTURE_CUBE; + info->format = d3d9_to_pipe_format(Format); + info->width0 = EdgeLength; + info->height0 = EdgeLength; + info->depth0 = 1; + if (Levels) + info->last_level = Levels - 1; + else + info->last_level = util_logbase2(EdgeLength); + info->array_size = 6; + info->nr_samples = 0; + info->bind = PIPE_BIND_SAMPLER_VIEW; + info->usage = PIPE_USAGE_DEFAULT; + info->flags = 0; + + if (Usage & D3DUSAGE_RENDERTARGET) + info->bind |= PIPE_BIND_RENDER_TARGET; + if (Usage & D3DUSAGE_DEPTHSTENCIL) + info->bind |= PIPE_BIND_DEPTH_STENCIL; + + if (Usage & D3DUSAGE_DYNAMIC) { + info->usage = PIPE_USAGE_DYNAMIC; + info->bind |= + PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE; + } + + This->surfaces = CALLOC(6 * (info->last_level + 1), sizeof(*This->surfaces)); + if (!This->surfaces) + return E_OUTOFMEMORY; + + hr = NineBaseTexture9_ctor(&This->base, pParams, D3DRTYPE_CUBETEXTURE, + Pool); + if (FAILED(hr)) + return hr; + This->base.pstype = 2; + + /* Create all the surfaces right away. + * They manage backing storage, and transfers (LockRect) are deferred + * to them. + */ + sfdesc.Format = Format; + sfdesc.Type = D3DRTYPE_SURFACE; + sfdesc.Usage = Usage; + sfdesc.Pool = Pool; + sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; + sfdesc.MultiSampleQuality = 0; + for (i = 0; i < (info->last_level + 1) * 6; ++i) { + sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, i / 6); + + hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), + This->base.base.resource, D3DRTYPE_CUBETEXTURE, + i / 6, i % 6, + &sfdesc, &This->surfaces[i]); + if (FAILED(hr)) + return hr; + } + for (i = 0; i < 6; ++i) /* width = 0 means empty, depth stays 1 */ + This->dirty_rect[i].depth = 1; + + return D3D_OK; +} + +static void +NineCubeTexture9_dtor( struct NineCubeTexture9 *This ) +{ + unsigned i; + + DBG("This=%p\n", This); + + if (This->surfaces) { + for (i = 0; i < This->base.base.info.last_level * 6; ++i) + NineUnknown_Destroy(&This->surfaces[i]->base.base); + FREE(This->surfaces); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT WINAPI +NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + *pDesc = This->surfaces[Level]->desc; + + return D3D_OK; +} + +HRESULT WINAPI +NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ) +{ + const unsigned s = Level * 6 + FaceType; + + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->surfaces[s])); + *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s]; + + return D3D_OK; +} + +HRESULT WINAPI +NineCubeTexture9_LockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + const unsigned s = Level * 6 + FaceType; + + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags); +} + +HRESULT WINAPI +NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ) +{ + const unsigned s = Level * 6 + FaceType; + + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + return NineSurface9_UnlockRect(This->surfaces[s]); +} + +HRESULT WINAPI +NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ) +{ + user_assert(FaceType < 6, D3DERR_INVALIDCALL); + + if (This->base.base.pool != D3DPOOL_MANAGED) { + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) + This->base.dirty_mip = TRUE; + return D3D_OK; + } + This->base.dirty = TRUE; + + BASETEX_REGISTER_UPDATE(&This->base); + + if (!pDirtyRect) { + u_box_origin_2d(This->base.base.info.width0, + This->base.base.info.height0, + &This->dirty_rect[FaceType]); + } else { + struct pipe_box box; + rect_to_pipe_box_clamp(&box, pDirtyRect); + u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType], + &box); + } + return D3D_OK; +} + +IDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineBaseTexture9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineBaseTexture9_SetLOD, + (void *)NineBaseTexture9_GetLOD, + (void *)NineBaseTexture9_GetLevelCount, + (void *)NineBaseTexture9_SetAutoGenFilterType, + (void *)NineBaseTexture9_GetAutoGenFilterType, + (void *)NineBaseTexture9_GenerateMipSubLevels, + (void *)NineCubeTexture9_GetLevelDesc, + (void *)NineCubeTexture9_GetCubeMapSurface, + (void *)NineCubeTexture9_LockRect, + (void *)NineCubeTexture9_UnlockRect, + (void *)NineCubeTexture9_AddDirtyRect +}; + +static const GUID *NineCubeTexture9_IIDs[] = { + &IID_IDirect3DCubeTexture9, + &IID_IDirect3DBaseTexture9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineCubeTexture9_new( struct NineDevice9 *pDevice, + UINT EdgeLength, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineCubeTexture9 **ppOut, + HANDLE *pSharedHandle ) +{ + NINE_DEVICE_CHILD_NEW(CubeTexture9, ppOut, pDevice, + EdgeLength, Levels, + Usage, Format, Pool, pSharedHandle); +} diff --git a/src/gallium/state_trackers/nine/cubetexture9.h b/src/gallium/state_trackers/nine/cubetexture9.h new file mode 100644 index 00000000000..e8594d35bb4 --- /dev/null +++ b/src/gallium/state_trackers/nine/cubetexture9.h @@ -0,0 +1,79 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_CUBETEXTURE9_H_ +#define _NINE_CUBETEXTURE9_H_ + +#include "basetexture9.h" +#include "surface9.h" + +struct NineCubeTexture9 +{ + struct NineBaseTexture9 base; + struct NineSurface9 **surfaces; + struct pipe_box dirty_rect[6]; /* covers all mip levels */ +}; +static INLINE struct NineCubeTexture9 * +NineCubeTexture9( void *data ) +{ + return (struct NineCubeTexture9 *)data; +} + +HRESULT +NineCubeTexture9_new( struct NineDevice9 *pDevice, + UINT EdgeLength, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineCubeTexture9 **ppOut, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ); + +HRESULT WINAPI +NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ); + +HRESULT WINAPI +NineCubeTexture9_LockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT WINAPI +NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ); + +HRESULT WINAPI +NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ); + +#endif /* _NINE_CUBETEXTURE9_H_ */ diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c new file mode 100644 index 00000000000..7d2142d03f1 --- /dev/null +++ b/src/gallium/state_trackers/nine/device9.c @@ -0,0 +1,3458 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "stateblock9.h" +#include "surface9.h" +#include "swapchain9.h" +#include "swapchain9ex.h" +#include "indexbuffer9.h" +#include "vertexbuffer9.h" +#include "vertexdeclaration9.h" +#include "vertexshader9.h" +#include "pixelshader9.h" +#include "query9.h" +#include "texture9.h" +#include "cubetexture9.h" +#include "volumetexture9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_ff.h" +#include "nine_dump.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "util/u_math.h" +#include "util/u_inlines.h" +#include "util/u_hash_table.h" +#include "util/u_format.h" +#include "util/u_surface.h" +#include "util/u_upload_mgr.h" +#include "hud/hud_context.h" + +#include "cso_cache/cso_context.h" + +#define DBG_CHANNEL DBG_DEVICE + +static void +NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset ) +{ + struct NineSurface9 *refSurf = NULL; + + assert(!This->is_recording); + + nine_state_set_defaults(&This->state, &This->caps, is_reset); + + This->state.viewport.X = 0; + This->state.viewport.Y = 0; + This->state.viewport.Width = 0; + This->state.viewport.Height = 0; + + This->state.scissor.minx = 0; + This->state.scissor.miny = 0; + This->state.scissor.maxx = 0xffff; + This->state.scissor.maxy = 0xffff; + + if (This->nswapchains && This->swapchains[0]->params.BackBufferCount) + refSurf = This->swapchains[0]->buffers[0]; + + if (refSurf) { + This->state.viewport.Width = refSurf->desc.Width; + This->state.viewport.Height = refSurf->desc.Height; + This->state.scissor.maxx = refSurf->desc.Width; + This->state.scissor.maxy = refSurf->desc.Height; + } + + if (This->nswapchains && This->swapchains[0]->params.EnableAutoDepthStencil) + This->state.rs[D3DRS_ZENABLE] = TRUE; + if (This->state.rs[D3DRS_ZENABLE]) + NineDevice9_SetDepthStencilSurface( + This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf); +} + +void +NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask ) +{ + struct pipe_context *pipe = This->pipe; + + if (mask & 0x1) { + struct pipe_constant_buffer cb; + cb.buffer_offset = 0; + + if (This->prefer_user_constbuf) { + cb.buffer = NULL; + cb.user_buffer = This->state.vs_const_f; + } else { + cb.buffer = This->constbuf_vs; + cb.user_buffer = NULL; + } + cb.buffer_size = This->constbuf_vs->width0; + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); + + if (This->prefer_user_constbuf) { + cb.user_buffer = This->state.ps_const_f; + } else { + cb.buffer = This->constbuf_ps; + } + cb.buffer_size = This->constbuf_ps->width0; + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); + } + + if (mask & 0x2) { + struct pipe_poly_stipple stipple; + memset(&stipple, ~0, sizeof(stipple)); + pipe->set_polygon_stipple(pipe, &stipple); + } + + This->state.changed.group = NINE_STATE_ALL; + This->state.changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1; + This->state.changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1; + This->state.changed.texture = NINE_PS_SAMPLERS_MASK | NINE_VS_SAMPLERS_MASK; +} + +#define GET_PCAP(n) pScreen->get_param(pScreen, PIPE_CAP_##n) +HRESULT +NineDevice9_ctor( struct NineDevice9 *This, + struct NineUnknownParams *pParams, + struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX ) +{ + unsigned i; + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) { return hr; } + + list_inithead(&This->update_textures); + + This->screen = pScreen; + This->caps = *pCaps; + This->d3d9 = pD3D9; + This->params = *pCreationParameters; + This->present = pPresentationGroup; + IDirect3D9_AddRef(This->d3d9); + ID3DPresentGroup_AddRef(This->present); + + This->pipe = This->screen->context_create(This->screen, NULL); + if (!This->pipe) { return E_OUTOFMEMORY; } /* guess */ + + This->cso = cso_create_context(This->pipe); + if (!This->cso) { return E_OUTOFMEMORY; } /* also a guess */ + + /* Create first, it messes up our state. */ + This->hud = hud_create(This->pipe, This->cso); /* NULL result is fine */ + + /* create implicit swapchains */ + This->nswapchains = ID3DPresentGroup_GetMultiheadCount(This->present); + This->swapchains = CALLOC(This->nswapchains, + sizeof(struct NineSwapChain9 *)); + if (!This->swapchains) { return E_OUTOFMEMORY; } + + for (i = 0; i < This->nswapchains; ++i) { + ID3DPresent *present; + + hr = ID3DPresentGroup_GetPresent(This->present, i, &present); + if (FAILED(hr)) + return hr; + + if (This->ex) { + D3DDISPLAYMODEEX *mode = NULL; + struct NineSwapChain9Ex **ret = + (struct NineSwapChain9Ex **)&This->swapchains[i]; + + if (This->pFullscreenDisplayMode) mode = &(This->pFullscreenDisplayMode[i]); + /* when this is a Device9Ex, it should create SwapChain9Exs */ + hr = NineSwapChain9Ex_new(This, TRUE, present, + &pPresentationParameters[i], pCTX, + This->params.hFocusWindow, mode, ret); + } else { + hr = NineSwapChain9_new(This, TRUE, present, + &pPresentationParameters[i], pCTX, + This->params.hFocusWindow, + &This->swapchains[i]); + } + + ID3DPresent_Release(present); + if (FAILED(hr)) + return hr; + NineUnknown_ConvertRefToBind(NineUnknown(This->swapchains[i])); + + hr = NineSwapChain9_GetBackBuffer(This->swapchains[i], 0, + D3DBACKBUFFER_TYPE_MONO, + (IDirect3DSurface9 **) + &This->state.rt[i]); + if (FAILED(hr)) + return hr; + NineUnknown_ConvertRefToBind(NineUnknown(This->state.rt[i])); + } + + This->cursor.software = FALSE; + This->cursor.hotspot.x = -1; + This->cursor.hotspot.y = -1; + { + struct pipe_resource tmpl; + tmpl.target = PIPE_TEXTURE_2D; + tmpl.format = PIPE_FORMAT_R8G8B8A8_UNORM; + tmpl.width0 = 64; + tmpl.height0 = 64; + tmpl.depth0 = 1; + tmpl.array_size = 1; + tmpl.last_level = 0; + tmpl.nr_samples = 0; + tmpl.usage = PIPE_USAGE_DEFAULT; + tmpl.bind = PIPE_BIND_CURSOR | PIPE_BIND_SAMPLER_VIEW; + tmpl.flags = 0; + + This->cursor.image = pScreen->resource_create(pScreen, &tmpl); + if (!This->cursor.image) + return D3DERR_OUTOFVIDEOMEMORY; + } + + /* Create constant buffers. */ + { + struct pipe_resource tmpl; + unsigned max_const_vs, max_const_ps; + + max_const_vs = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) / + sizeof(float[4]), + NINE_MAX_CONST_ALL); + max_const_ps = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) / + sizeof(float[4]), + NINE_MAX_CONST_ALL); + + This->max_vs_const_f = max_const_vs - + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4); + This->max_ps_const_f = max_const_ps - + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4); + + /* Include space for I,B constants for user constbuf. */ + This->state.vs_const_f = CALLOC(NINE_MAX_CONST_ALL, sizeof(float[4])); + This->state.ps_const_f = CALLOC(NINE_MAX_CONST_ALL, sizeof(float[4])); + if (!This->state.vs_const_f || !This->state.ps_const_f) + return E_OUTOFMEMORY; + + if (strstr(pScreen->get_name(pScreen), "AMD") || + strstr(pScreen->get_name(pScreen), "ATI")) + This->prefer_user_constbuf = TRUE; + + tmpl.target = PIPE_BUFFER; + tmpl.format = PIPE_FORMAT_R8_UNORM; + tmpl.height0 = 1; + tmpl.depth0 = 1; + tmpl.array_size = 1; + tmpl.last_level = 0; + tmpl.nr_samples = 0; + tmpl.usage = PIPE_USAGE_DYNAMIC; + tmpl.bind = PIPE_BIND_CONSTANT_BUFFER; + tmpl.flags = 0; + + tmpl.width0 = max_const_vs * sizeof(float[4]); + This->constbuf_vs = pScreen->resource_create(pScreen, &tmpl); + + tmpl.width0 = max_const_ps * sizeof(float[4]); + This->constbuf_ps = pScreen->resource_create(pScreen, &tmpl); + + if (!This->constbuf_vs || !This->constbuf_ps) + return E_OUTOFMEMORY; + } + + This->vs_bool_true = pScreen->get_shader_param(pScreen, + PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_INTEGERS) ? 0xFFFFFFFF : fui(1.0f); + This->ps_bool_true = pScreen->get_shader_param(pScreen, + PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_INTEGERS) ? 0xFFFFFFFF : fui(1.0f); + + /* Allocate upload helper for drivers that suck (from st pov ;). */ + { + unsigned bind = 0; + + This->driver_caps.user_vbufs = GET_PCAP(USER_VERTEX_BUFFERS); + This->driver_caps.user_ibufs = GET_PCAP(USER_INDEX_BUFFERS); + + if (!This->driver_caps.user_vbufs) bind |= PIPE_BIND_VERTEX_BUFFER; + if (!This->driver_caps.user_ibufs) bind |= PIPE_BIND_INDEX_BUFFER; + if (bind) + This->upload = u_upload_create(This->pipe, 1 << 20, 4, bind); + } + + This->driver_caps.window_space_position_support = GET_PCAP(TGSI_VS_WINDOW_SPACE_POSITION); + + nine_ff_init(This); /* initialize fixed function code */ + + NineDevice9_SetDefaultState(This, FALSE); + NineDevice9_RestoreNonCSOState(This, ~0); + + This->update = &This->state; + nine_update_state(This, ~0); + + /* Is just used to pass the parameter from NineDevice9Ex_ctor */ + This->pFullscreenDisplayMode = NULL; + + ID3DPresentGroup_Release(This->present); + + return D3D_OK; +} +#undef GET_PCAP + +void +NineDevice9_dtor( struct NineDevice9 *This ) +{ + unsigned i; + + DBG("This=%p\n", This); + + if (This->pipe && This->cso) + nine_pipe_context_clear(This); + nine_ff_fini(This); + nine_state_clear(&This->state, TRUE); + + if (This->upload) + u_upload_destroy(This->upload); + + nine_bind(&This->record, NULL); + + pipe_resource_reference(&This->constbuf_vs, NULL); + pipe_resource_reference(&This->constbuf_ps, NULL); + FREE(This->state.vs_const_f); + FREE(This->state.ps_const_f); + + if (This->swapchains) { + for (i = 0; i < This->nswapchains; ++i) + NineUnknown_Unbind(NineUnknown(This->swapchains[i])); + FREE(This->swapchains); + } + + /* state stuff */ + if (This->pipe) { + if (This->cso) { + cso_release_all(This->cso); + cso_destroy_context(This->cso); + } + if (This->pipe->destroy) { This->pipe->destroy(This->pipe); } + } + + if (This->present) { ID3DPresentGroup_Release(This->present); } + if (This->d3d9) { IDirect3D9_Release(This->d3d9); } + + NineUnknown_dtor(&This->base); +} + +struct pipe_screen * +NineDevice9_GetScreen( struct NineDevice9 *This ) +{ + return This->screen; +} + +struct pipe_context * +NineDevice9_GetPipe( struct NineDevice9 *This ) +{ + return This->pipe; +} + +struct cso_context * +NineDevice9_GetCSO( struct NineDevice9 *This ) +{ + return This->cso; +} + +const D3DCAPS9 * +NineDevice9_GetCaps( struct NineDevice9 *This ) +{ + return &This->caps; +} + +static INLINE void +NineDevice9_PauseRecording( struct NineDevice9 *This ) +{ + if (This->record) { + This->update = &This->state; + This->is_recording = FALSE; + } +} + +static INLINE void +NineDevice9_ResumeRecording( struct NineDevice9 *This ) +{ + if (This->record) { + This->update = &This->record->state; + This->is_recording = TRUE; + } +} + +HRESULT WINAPI +NineDevice9_TestCooperativeLevel( struct NineDevice9 *This ) +{ + return D3D_OK; /* TODO */ +} + +UINT WINAPI +NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This ) +{ + return This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY); +} + +HRESULT WINAPI +NineDevice9_EvictManagedResources( struct NineDevice9 *This ) +{ + /* We don't really need to do anything here, but might want to free up + * the GPU virtual address space by killing pipe_resources. + */ + STUB(D3D_OK); +} + +HRESULT WINAPI +NineDevice9_GetDirect3D( struct NineDevice9 *This, + IDirect3D9 **ppD3D9 ) +{ + user_assert(ppD3D9 != NULL, E_POINTER); + IDirect3D9_AddRef(This->d3d9); + *ppD3D9 = This->d3d9; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ) +{ + user_assert(pCaps != NULL, D3DERR_INVALIDCALL); + *pCaps = This->caps; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetDisplayMode( struct NineDevice9 *This, + UINT iSwapChain, + D3DDISPLAYMODE *pMode ) +{ + DBG("This=%p iSwapChain=%u pMode=%p\n", This, iSwapChain, pMode); + + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + return NineSwapChain9_GetDisplayMode(This->swapchains[iSwapChain], pMode); +} + +HRESULT WINAPI +NineDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ) +{ + user_assert(pParameters != NULL, D3DERR_INVALIDCALL); + *pParameters = This->params; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ) +{ + /* TODO: hardware cursor */ + struct NineSurface9 *surf = NineSurface9(pCursorBitmap); + struct pipe_context *pipe = This->pipe; + struct pipe_box box; + struct pipe_transfer *transfer; + void *ptr; + + DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u " + "pCursorBitmap=%p\n", This, XHotSpot, YHotSpot, pCursorBitmap); + + user_assert(pCursorBitmap, D3DERR_INVALIDCALL); + + This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0); + This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0); + + u_box_origin_2d(This->cursor.w, This->cursor.h, &box); + + ptr = pipe->transfer_map(pipe, This->cursor.image, 0, + PIPE_TRANSFER_WRITE | + PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE, + &box, &transfer); + if (!ptr) + ret_err("Failed to update cursor image.\n", D3DERR_DRIVERINTERNALERROR); + + This->cursor.hotspot.x = XHotSpot; + This->cursor.hotspot.y = YHotSpot; + + /* Copy cursor image to internal storage. */ + { + D3DLOCKED_RECT lock; + HRESULT hr; + const struct util_format_description *sfmt = + util_format_description(surf->base.info.format); + assert(sfmt); + + hr = NineSurface9_LockRect(surf, &lock, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) + ret_err("Failed to map cursor source image.\n", + D3DERR_DRIVERINTERNALERROR); + + sfmt->unpack_rgba_8unorm(ptr, transfer->stride, + lock.pBits, lock.Pitch, + This->cursor.w, This->cursor.h); + + if (!This->cursor.software && + This->cursor.w == 32 && This->cursor.h == 32) + ID3DPresent_SetCursor(This->swapchains[0]->present, + lock.pBits, &This->cursor.hotspot, + This->cursor.visible); + + NineSurface9_UnlockRect(surf); + } + pipe->transfer_unmap(pipe, transfer); + + return D3D_OK; +} + +void WINAPI +NineDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ) +{ + struct NineSwapChain9 *swap = This->swapchains[0]; + + This->cursor.pos.x = X; + This->cursor.pos.y = Y; + + if (!This->cursor.software) + ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos); +} + +BOOL WINAPI +NineDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ) +{ + BOOL old = This->cursor.visible; + This->cursor.visible = bShow && (This->cursor.hotspot.x != -1); + if (!This->cursor.software) + ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow); + + return old; +} + +HRESULT WINAPI +NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ) +{ + struct NineSwapChain9 *swapchain, *tmplt = This->swapchains[0]; + ID3DPresent *present; + HRESULT hr; + + user_assert(pPresentationParameters, D3DERR_INVALIDCALL); + + hr = ID3DPresentGroup_CreateAdditionalPresent(This->present, pPresentationParameters, &present); + + if (FAILED(hr)) + return hr; + + hr = NineSwapChain9_new(This, FALSE, present, pPresentationParameters, + tmplt->actx, + tmplt->params.hDeviceWindow, + &swapchain); + if (FAILED(hr)) + return hr; + + *pSwapChain = (IDirect3DSwapChain9 *)swapchain; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetSwapChain( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSwapChain9 **pSwapChain ) +{ + user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL); + + *pSwapChain = NULL; + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->swapchains[iSwapChain])); + *pSwapChain = (IDirect3DSwapChain9 *)This->swapchains[iSwapChain]; + + return D3D_OK; +} + +UINT WINAPI +NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ) +{ + return This->nswapchains; +} + +HRESULT WINAPI +NineDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT hr = D3D_OK; + unsigned i; + + DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters); + + for (i = 0; i < This->nswapchains; ++i) { + D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; + hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL); + if (FAILED(hr)) + return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST; + } + + nine_pipe_context_clear(This); + nine_state_clear(&This->state, TRUE); + + NineDevice9_SetDefaultState(This, TRUE); + NineDevice9_SetRenderTarget( + This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]); + /* XXX: better use GetBackBuffer here ? */ + + return hr; +} + +HRESULT WINAPI +NineDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ) +{ + unsigned i; + HRESULT hr; + + /* XXX is this right? */ + for (i = 0; i < This->nswapchains; ++i) { + hr = NineSwapChain9_Present(This->swapchains[i], pSourceRect, pDestRect, + hDestWindowOverride, pDirtyRegion, 0); + if (FAILED(hr)) { return hr; } + } + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL); + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + return NineSwapChain9_GetBackBuffer(This->swapchains[iSwapChain], + iBackBuffer, Type, ppBackBuffer); +} + +HRESULT WINAPI +NineDevice9_GetRasterStatus( struct NineDevice9 *This, + UINT iSwapChain, + D3DRASTER_STATUS *pRasterStatus ) +{ + user_assert(pRasterStatus != NULL, D3DERR_INVALIDCALL); + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + return NineSwapChain9_GetRasterStatus(This->swapchains[iSwapChain], + pRasterStatus); +} + +HRESULT WINAPI +NineDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ) +{ + STUB(D3DERR_INVALIDCALL); +} + +void WINAPI +NineDevice9_SetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + DWORD Flags, + const D3DGAMMARAMP *pRamp ) +{ + DBG("This=%p iSwapChain=%u Flags=%x pRamp=%p\n", This, + iSwapChain, Flags, pRamp); + + user_warn(iSwapChain >= This->nswapchains); + user_warn(!pRamp); + + if (pRamp && (iSwapChain < This->nswapchains)) { + struct NineSwapChain9 *swap = This->swapchains[iSwapChain]; + swap->gamma = *pRamp; + ID3DPresent_SetGammaRamp(swap->present, pRamp, swap->params.hDeviceWindow); + } +} + +void WINAPI +NineDevice9_GetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + D3DGAMMARAMP *pRamp ) +{ + DBG("This=%p iSwapChain=%u pRamp=%p\n", This, iSwapChain, pRamp); + + user_warn(iSwapChain >= This->nswapchains); + user_warn(!pRamp); + + if (pRamp && (iSwapChain < This->nswapchains)) + *pRamp = This->swapchains[iSwapChain]->gamma; +} + +HRESULT WINAPI +NineDevice9_CreateTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DTexture9 **ppTexture, + HANDLE *pSharedHandle ) +{ + struct NineTexture9 *tex; + HRESULT hr; + + DBG("This=%p Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s " + "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Levels, + nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format), + nine_D3DPOOL_to_str(Pool), ppTexture, pSharedHandle); + + Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DMAP | + D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET | + D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI; + + user_assert(Width && Height, D3DERR_INVALIDCALL); + user_assert(!pSharedHandle || This->ex, D3DERR_INVALIDCALL); + /* When is used shared handle, Pool must be + * SYSTEMMEM with Levels 1 or DEFAULT with any Levels */ + user_assert(!pSharedHandle || Pool != D3DPOOL_SYSTEMMEM || Levels == 1, + D3DERR_INVALIDCALL); + user_assert(!pSharedHandle || Pool == D3DPOOL_SYSTEMMEM || Pool == D3DPOOL_DEFAULT, + D3DERR_INVALIDCALL); + user_assert((Usage != D3DUSAGE_AUTOGENMIPMAP || Levels <= 1), D3DERR_INVALIDCALL); + + hr = NineTexture9_new(This, Width, Height, Levels, Usage, Format, Pool, + &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppTexture = (IDirect3DTexture9 *)tex; + + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateVolumeTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Depth, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DVolumeTexture9 **ppVolumeTexture, + HANDLE *pSharedHandle ) +{ + struct NineVolumeTexture9 *tex; + HRESULT hr; + + DBG("This=%p Width=%u Height=%u Depth=%u Levels=%u Usage=%s Format=%s Pool=%s " + "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Depth, Levels, + nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format), + nine_D3DPOOL_to_str(Pool), ppVolumeTexture, pSharedHandle); + + Usage &= D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | + D3DUSAGE_SOFTWAREPROCESSING; + + user_assert(Width && Height && Depth, D3DERR_INVALIDCALL); + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + hr = NineVolumeTexture9_new(This, Width, Height, Depth, Levels, + Usage, Format, Pool, &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppVolumeTexture = (IDirect3DVolumeTexture9 *)tex; + + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateCubeTexture( struct NineDevice9 *This, + UINT EdgeLength, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DCubeTexture9 **ppCubeTexture, + HANDLE *pSharedHandle ) +{ + struct NineCubeTexture9 *tex; + HRESULT hr; + + DBG("This=%p EdgeLength=%u Levels=%u Usage=%s Format=%s Pool=%s ppOut=%p " + "pSharedHandle=%p\n", This, EdgeLength, Levels, + nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format), + nine_D3DPOOL_to_str(Pool), ppCubeTexture, pSharedHandle); + + Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC | + D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET | + D3DUSAGE_SOFTWAREPROCESSING; + + user_assert(EdgeLength, D3DERR_INVALIDCALL); + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + hr = NineCubeTexture9_new(This, EdgeLength, Levels, Usage, Format, Pool, + &tex, pSharedHandle); + if (SUCCEEDED(hr)) + *ppCubeTexture = (IDirect3DCubeTexture9 *)tex; + + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateVertexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + DWORD FVF, + D3DPOOL Pool, + IDirect3DVertexBuffer9 **ppVertexBuffer, + HANDLE *pSharedHandle ) +{ + struct NineVertexBuffer9 *buf; + HRESULT hr; + D3DVERTEXBUFFER_DESC desc; + + DBG("This=%p Length=%u Usage=%x FVF=%x Pool=%u ppOut=%p pSharedHandle=%p\n", + This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); + + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE); + + desc.Format = D3DFMT_VERTEXDATA; + desc.Type = D3DRTYPE_VERTEXBUFFER; + desc.Usage = Usage & + (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | + D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | + D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI | + D3DUSAGE_WRITEONLY); + desc.Pool = Pool; + desc.Size = Length; + desc.FVF = FVF; + + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL); + + hr = NineVertexBuffer9_new(This, &desc, &buf); + if (SUCCEEDED(hr)) + *ppVertexBuffer = (IDirect3DVertexBuffer9 *)buf; + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateIndexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DIndexBuffer9 **ppIndexBuffer, + HANDLE *pSharedHandle ) +{ + struct NineIndexBuffer9 *buf; + HRESULT hr; + D3DINDEXBUFFER_DESC desc; + + DBG("This=%p Length=%u Usage=%x Format=%s Pool=%u ppOut=%p " + "pSharedHandle=%p\n", This, Length, Usage, + d3dformat_to_string(Format), Pool, ppIndexBuffer, pSharedHandle); + + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE); + + desc.Format = Format; + desc.Type = D3DRTYPE_INDEXBUFFER; + desc.Usage = Usage & + (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | + D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | + D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY); + desc.Pool = Pool; + desc.Size = Length; + + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL); + + hr = NineIndexBuffer9_new(This, &desc, &buf); + if (SUCCEEDED(hr)) + *ppIndexBuffer = (IDirect3DIndexBuffer9 *)buf; + return hr; +} + +static HRESULT +create_zs_or_rt_surface(struct NineDevice9 *This, + unsigned type, /* 0 = RT, 1 = ZS, 2 = plain */ + D3DPOOL Pool, + UINT Width, UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard_or_Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle) +{ + struct NineSurface9 *surface; + struct pipe_screen *screen = This->screen; + struct pipe_resource *resource = NULL; + HRESULT hr; + D3DSURFACE_DESC desc; + struct pipe_resource templ; + + DBG("This=%p type=%u Pool=%s Width=%u Height=%u Format=%s MS=%u Quality=%u " + "Discard_or_Lockable=%i ppSurface=%p pSharedHandle=%p\n", + This, type, nine_D3DPOOL_to_str(Pool), Width, Height, + d3dformat_to_string(Format), MultiSample, MultisampleQuality, + Discard_or_Lockable, ppSurface, pSharedHandle); + + if (pSharedHandle) + DBG("FIXME Used shared handle! This option isn't probably handled correctly!\n"); + + user_assert(Width && Height, D3DERR_INVALIDCALL); + user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL); + + templ.target = PIPE_TEXTURE_2D; + templ.format = d3d9_to_pipe_format(Format); + templ.width0 = Width; + templ.height0 = Height; + templ.depth0 = 1; + templ.array_size = 1; + templ.last_level = 0; + templ.nr_samples = (unsigned)MultiSample; + templ.usage = PIPE_USAGE_DEFAULT; + templ.flags = 0; + templ.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */ + switch (type) { + case 0: templ.bind |= PIPE_BIND_RENDER_TARGET; break; + case 1: templ.bind |= PIPE_BIND_DEPTH_STENCIL; break; + default: + assert(type == 2); + break; + } + + desc.Format = Format; + desc.Type = D3DRTYPE_SURFACE; + desc.Usage = 0; + desc.Pool = Pool; + desc.MultiSampleType = MultiSample; + desc.MultiSampleQuality = MultisampleQuality; + desc.Width = Width; + desc.Height = Height; + switch (type) { + case 0: desc.Usage = D3DUSAGE_RENDERTARGET; break; + case 1: desc.Usage = D3DUSAGE_DEPTHSTENCIL; break; + default: break; + } + + if (Pool == D3DPOOL_DEFAULT && Format != D3DFMT_NULL) { + /* resource_create doesn't return an error code, so check format here */ + user_assert(CHECK_PIPE_RESOURCE_TEMPLATE(templ), D3DERR_INVALIDCALL); + resource = screen->resource_create(screen, &templ); + user_assert(resource, D3DERR_OUTOFVIDEOMEMORY); + if (Discard_or_Lockable && (desc.Usage & D3DUSAGE_RENDERTARGET)) + resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + } else { + resource = NULL; + } + hr = NineSurface9_new(This, NULL, resource, 0, 0, 0, &desc, &surface); + pipe_resource_reference(&resource, NULL); + + if (SUCCEEDED(hr)) + *ppSurface = (IDirect3DSurface9 *)surface; + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateRenderTarget( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + return create_zs_or_rt_surface(This, 0, D3DPOOL_DEFAULT, + Width, Height, Format, + MultiSample, MultisampleQuality, + Lockable, ppSurface, pSharedHandle); +} + +HRESULT WINAPI +NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + return create_zs_or_rt_surface(This, 1, D3DPOOL_DEFAULT, + Width, Height, Format, + MultiSample, MultisampleQuality, + Discard, ppSurface, pSharedHandle); +} + +HRESULT WINAPI +NineDevice9_UpdateSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestinationSurface, + const POINT *pDestPoint ) +{ + struct NineSurface9 *dst = NineSurface9(pDestinationSurface); + struct NineSurface9 *src = NineSurface9(pSourceSurface); + + DBG("This=%p pSourceSurface=%p pDestinationSurface=%p " + "pSourceRect=%p pDestPoint=%p\n", This, + pSourceSurface, pDestinationSurface, pSourceRect, pDestPoint); + if (pSourceRect) + DBG("pSourceRect = (%u,%u)-(%u,%u)\n", + pSourceRect->left, pSourceRect->top, + pSourceRect->right, pSourceRect->bottom); + if (pDestPoint) + DBG("pDestPoint = (%u,%u)\n", pDestPoint->x, pDestPoint->y); + + user_assert(dst->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(src->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + + user_assert(dst->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); + user_assert(src->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); + + return NineSurface9_CopySurface(dst, src, pDestPoint, pSourceRect); +} + +HRESULT WINAPI +NineDevice9_UpdateTexture( struct NineDevice9 *This, + IDirect3DBaseTexture9 *pSourceTexture, + IDirect3DBaseTexture9 *pDestinationTexture ) +{ + struct NineBaseTexture9 *dstb = NineBaseTexture9(pDestinationTexture); + struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture); + unsigned l, m; + unsigned last_level = dstb->base.info.last_level; + + DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This, + pSourceTexture, pDestinationTexture); + + user_assert(pSourceTexture != pDestinationTexture, D3DERR_INVALIDCALL); + + user_assert(dstb->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + user_assert(srcb->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + + if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) { + /* Only the first level is updated, the others regenerated. */ + last_level = 0; + } else { + user_assert(!(srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP), D3DERR_INVALIDCALL); + } + + user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL); + + /* TODO: We can restrict the update to the dirty portions of the source. + * Yes, this seems silly, but it's what MSDN says ... + */ + + /* Find src level that matches dst level 0: */ + user_assert(srcb->base.info.width0 >= dstb->base.info.width0 && + srcb->base.info.height0 >= dstb->base.info.height0 && + srcb->base.info.depth0 >= dstb->base.info.depth0, + D3DERR_INVALIDCALL); + for (m = 0; m <= srcb->base.info.last_level; ++m) { + unsigned w = u_minify(srcb->base.info.width0, m); + unsigned h = u_minify(srcb->base.info.height0, m); + unsigned d = u_minify(srcb->base.info.depth0, m); + + if (w == dstb->base.info.width0 && + h == dstb->base.info.height0 && + d == dstb->base.info.depth0) + break; + } + user_assert(m <= srcb->base.info.last_level, D3DERR_INVALIDCALL); + + last_level = MIN2(last_level, srcb->base.info.last_level - m); + + if (dstb->base.type == D3DRTYPE_TEXTURE) { + struct NineTexture9 *dst = NineTexture9(dstb); + struct NineTexture9 *src = NineTexture9(srcb); + + for (l = 0; l <= last_level; ++l, ++m) + NineSurface9_CopySurface(dst->surfaces[l], + src->surfaces[m], NULL, NULL); + } else + if (dstb->base.type == D3DRTYPE_CUBETEXTURE) { + struct NineCubeTexture9 *dst = NineCubeTexture9(dstb); + struct NineCubeTexture9 *src = NineCubeTexture9(srcb); + unsigned z; + + /* GPUs usually have them stored as arrays of mip-mapped 2D textures. */ + for (z = 0; z < 6; ++z) { + for (l = 0; l <= last_level; ++l, ++m) { + NineSurface9_CopySurface(dst->surfaces[l * 6 + z], + src->surfaces[m * 6 + z], NULL, NULL); + } + m -= l; + } + } else + if (dstb->base.type == D3DRTYPE_VOLUMETEXTURE) { + struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb); + struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb); + + for (l = 0; l <= last_level; ++l, ++m) + NineVolume9_CopyVolume(dst->volumes[l], + src->volumes[m], 0, 0, 0, NULL); + } else{ + assert(!"invalid texture type"); + } + + if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) + NineBaseTexture9_GenerateMipSubLevels(dstb); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetRenderTargetData( struct NineDevice9 *This, + IDirect3DSurface9 *pRenderTarget, + IDirect3DSurface9 *pDestSurface ) +{ + struct NineSurface9 *dst = NineSurface9(pDestSurface); + struct NineSurface9 *src = NineSurface9(pRenderTarget); + + DBG("This=%p pRenderTarget=%p pDestSurface=%p\n", + This, pRenderTarget, pDestSurface); + + user_assert(dst->desc.Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + user_assert(src->desc.Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + user_assert(dst->desc.MultiSampleType < 2, D3DERR_INVALIDCALL); + user_assert(src->desc.MultiSampleType < 2, D3DERR_INVALIDCALL); + + return NineSurface9_CopySurface(dst, src, NULL, NULL); +} + +HRESULT WINAPI +NineDevice9_GetFrontBufferData( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSurface9 *pDestSurface ) +{ + DBG("This=%p iSwapChain=%u pDestSurface=%p\n", This, + iSwapChain, pDestSurface); + + user_assert(pDestSurface != NULL, D3DERR_INVALIDCALL); + user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL); + + return NineSwapChain9_GetFrontBufferData(This->swapchains[iSwapChain], + pDestSurface); +} + +HRESULT WINAPI +NineDevice9_StretchRect( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestSurface, + const RECT *pDestRect, + D3DTEXTUREFILTERTYPE Filter ) +{ + struct pipe_screen *screen = This->screen; + struct pipe_context *pipe = This->pipe; + struct NineSurface9 *dst = NineSurface9(pDestSurface); + struct NineSurface9 *src = NineSurface9(pSourceSurface); + struct pipe_resource *dst_res = NineSurface9_GetResource(dst); + struct pipe_resource *src_res = NineSurface9_GetResource(src); + const boolean zs = util_format_is_depth_or_stencil(dst_res->format); + struct pipe_blit_info blit; + boolean scaled, clamped, ms, flip_x = FALSE, flip_y = FALSE; + + DBG("This=%p pSourceSurface=%p pSourceRect=%p pDestSurface=%p " + "pDestRect=%p Filter=%u\n", + This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter); + if (pSourceRect) + DBG("pSourceRect=(%u,%u)-(%u,%u)\n", + pSourceRect->left, pSourceRect->top, + pSourceRect->right, pSourceRect->bottom); + if (pDestRect) + DBG("pSourceRect=(%u,%u)-(%u,%u)\n", pDestRect->left, pDestRect->top, + pDestRect->right, pDestRect->bottom); + + user_assert(!zs || !This->in_scene, D3DERR_INVALIDCALL); + user_assert(!zs || !pSourceRect || + (pSourceRect->left == 0 && + pSourceRect->top == 0 && + pSourceRect->right == src->desc.Width && + pSourceRect->bottom == src->desc.Height), D3DERR_INVALIDCALL); + user_assert(!zs || !pDestRect || + (pDestRect->left == 0 && + pDestRect->top == 0 && + pDestRect->right == dst->desc.Width && + pDestRect->bottom == dst->desc.Height), D3DERR_INVALIDCALL); + user_assert(!zs || + (dst->desc.Width == src->desc.Width && + dst->desc.Height == src->desc.Height), D3DERR_INVALIDCALL); + user_assert(zs || !util_format_is_depth_or_stencil(src_res->format), + D3DERR_INVALIDCALL); + user_assert(!zs || dst->desc.Format == src->desc.Format, + D3DERR_INVALIDCALL); + user_assert(screen->is_format_supported(screen, src_res->format, + src_res->target, + src_res->nr_samples, + PIPE_BIND_SAMPLER_VIEW), + D3DERR_INVALIDCALL); + user_assert(dst->base.pool == D3DPOOL_DEFAULT && + src->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + /* We might want to permit these, but wine thinks we shouldn't. */ + user_assert(!pDestRect || + (pDestRect->left <= pDestRect->right && + pDestRect->top <= pDestRect->bottom), D3DERR_INVALIDCALL); + user_assert(!pSourceRect || + (pSourceRect->left <= pSourceRect->right && + pSourceRect->top <= pSourceRect->bottom), D3DERR_INVALIDCALL); + + blit.dst.resource = dst_res; + blit.dst.level = dst->level; + blit.dst.box.z = dst->layer; + blit.dst.box.depth = 1; + blit.dst.format = dst_res->format; + if (pDestRect) { + flip_x = pDestRect->left > pDestRect->right; + if (flip_x) { + blit.dst.box.x = pDestRect->right; + blit.dst.box.width = pDestRect->left - pDestRect->right; + } else { + blit.dst.box.x = pDestRect->left; + blit.dst.box.width = pDestRect->right - pDestRect->left; + } + flip_y = pDestRect->top > pDestRect->bottom; + if (flip_y) { + blit.dst.box.y = pDestRect->bottom; + blit.dst.box.height = pDestRect->top - pDestRect->bottom; + } else { + blit.dst.box.y = pDestRect->top; + blit.dst.box.height = pDestRect->bottom - pDestRect->top; + } + } else { + blit.dst.box.x = 0; + blit.dst.box.y = 0; + blit.dst.box.width = dst->desc.Width; + blit.dst.box.height = dst->desc.Height; + } + blit.src.resource = src_res; + blit.src.level = src->level; + blit.src.box.z = src->layer; + blit.src.box.depth = 1; + blit.src.format = src_res->format; + if (pSourceRect) { + if (flip_x ^ (pSourceRect->left > pSourceRect->right)) { + blit.src.box.x = pSourceRect->right; + blit.src.box.width = pSourceRect->left - pSourceRect->right; + } else { + blit.src.box.x = pSourceRect->left; + blit.src.box.width = pSourceRect->right - pSourceRect->left; + } + if (flip_y ^ (pSourceRect->top > pSourceRect->bottom)) { + blit.src.box.y = pSourceRect->bottom; + blit.src.box.height = pSourceRect->top - pSourceRect->bottom; + } else { + blit.src.box.y = pSourceRect->top; + blit.src.box.height = pSourceRect->bottom - pSourceRect->top; + } + } else { + blit.src.box.x = flip_x ? src->desc.Width : 0; + blit.src.box.y = flip_y ? src->desc.Height : 0; + blit.src.box.width = flip_x ? -src->desc.Width : src->desc.Width; + blit.src.box.height = flip_y ? -src->desc.Height : src->desc.Height; + } + blit.mask = zs ? PIPE_MASK_ZS : PIPE_MASK_RGBA; + blit.filter = Filter == D3DTEXF_LINEAR ? + PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; + blit.scissor_enable = FALSE; + + /* If both of a src and dst dimension are negative, flip them. */ + if (blit.dst.box.width < 0 && blit.src.box.width < 0) { + blit.dst.box.width = -blit.dst.box.width; + blit.src.box.width = -blit.src.box.width; + } + if (blit.dst.box.height < 0 && blit.src.box.height < 0) { + blit.dst.box.height = -blit.dst.box.height; + blit.src.box.height = -blit.src.box.height; + } + scaled = + blit.dst.box.width != blit.src.box.width || + blit.dst.box.height != blit.src.box.height; + + user_assert(!scaled || dst != src, D3DERR_INVALIDCALL); + user_assert(!scaled || + !NineSurface9_IsOffscreenPlain(dst) || + NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL); + user_assert(!scaled || + (!util_format_is_compressed(dst->base.info.format) && + !util_format_is_compressed(src->base.info.format)), + D3DERR_INVALIDCALL); + + user_warn(src == dst && + u_box_test_intersection_2d(&blit.src.box, &blit.dst.box)); + + /* Check for clipping/clamping: */ + { + struct pipe_box box; + int xy; + + xy = u_box_clip_2d(&box, &blit.dst.box, + dst->desc.Width, dst->desc.Height); + if (xy < 0) + return D3D_OK; + if (xy == 0) + xy = u_box_clip_2d(&box, &blit.src.box, + src->desc.Width, src->desc.Height); + clamped = !!xy; + } + + ms = (dst->desc.MultiSampleType | 1) != (src->desc.MultiSampleType | 1); + + if (clamped || scaled || (blit.dst.format != blit.src.format) || ms) { + DBG("using pipe->blit()\n"); + /* TODO: software scaling */ + user_assert(screen->is_format_supported(screen, dst_res->format, + dst_res->target, + dst_res->nr_samples, + zs ? PIPE_BIND_DEPTH_STENCIL : + PIPE_BIND_RENDER_TARGET), + D3DERR_INVALIDCALL); + + pipe->blit(pipe, &blit); + } else { + assert(blit.dst.box.x >= 0 && blit.dst.box.y >= 0 && + blit.src.box.x >= 0 && blit.src.box.y >= 0 && + blit.dst.box.x + blit.dst.box.width <= dst->desc.Width && + blit.src.box.x + blit.src.box.width <= src->desc.Width && + blit.dst.box.y + blit.dst.box.height <= dst->desc.Height && + blit.src.box.y + blit.src.box.height <= src->desc.Height); + /* Or drivers might crash ... */ + DBG("Using resource_copy_region.\n"); + pipe->resource_copy_region(pipe, + blit.dst.resource, blit.dst.level, + blit.dst.box.x, blit.dst.box.y, blit.dst.box.z, + blit.src.resource, blit.src.level, + &blit.src.box); + } + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ) +{ + struct pipe_context *pipe = This->pipe; + struct NineSurface9 *surf = NineSurface9(pSurface); + struct pipe_surface *psurf; + unsigned x, y, w, h; + union pipe_color_union rgba; + boolean fallback; + + DBG("This=%p pSurface=%p pRect=%p color=%08x\n", This, + pSurface, pRect, color); + if (pRect) + DBG("pRect=(%u,%u)-(%u,%u)\n", pRect->left, pRect->top, + pRect->right, pRect->bottom); + + user_assert(surf->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + user_assert((surf->base.usage & D3DUSAGE_RENDERTARGET) || + NineSurface9_IsOffscreenPlain(surf), D3DERR_INVALIDCALL); + + if (pRect) { + x = pRect->left; + y = pRect->top; + w = pRect->right - pRect->left; + h = pRect->bottom - pRect->top; + } else{ + x = 0; + y = 0; + w = surf->desc.Width; + h = surf->desc.Height; + } + d3dcolor_to_pipe_color_union(&rgba, color); + + fallback = + !This->screen->is_format_supported(This->screen, surf->base.info.format, + surf->base.info.target, + surf->base.info.nr_samples, + PIPE_BIND_RENDER_TARGET); + if (!fallback) { + psurf = NineSurface9_GetSurface(surf, 0); + if (!psurf) + fallback = TRUE; + } + + if (!fallback) { + pipe->clear_render_target(pipe, psurf, &rgba, x, y, w, h); + } else { + D3DLOCKED_RECT lock; + union util_color uc; + HRESULT hr; + /* XXX: lock pRect and fix util_fill_rect */ + hr = NineSurface9_LockRect(surf, &lock, NULL, 0); + if (FAILED(hr)) + return hr; + util_pack_color_ub(color >> 16, color >> 8, color >> 0, color >> 24, + surf->base.info.format, &uc); + util_fill_rect(lock.pBits, surf->base.info.format,lock.Pitch, + x, y, w, h, &uc); + NineSurface9_UnlockRect(surf); + } + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + HRESULT hr; + + DBG("This=%p Width=%u Height=%u Format=%s(0x%x) Pool=%u " + "ppSurface=%p pSharedHandle=%p\n", This, + Width, Height, d3dformat_to_string(Format), Format, Pool, + ppSurface, pSharedHandle); + + user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT + || Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL); + + /* Can be used with StretchRect and ColorFill. It's also always lockable. + */ + hr = create_zs_or_rt_surface(This, 2, Pool, Width, Height, + Format, + D3DMULTISAMPLE_NONE, 0, + TRUE, + ppSurface, pSharedHandle); + if (FAILED(hr)) + DBG("Failed to create surface.\n"); + return hr; +} + +HRESULT WINAPI +NineDevice9_SetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 *pRenderTarget ) +{ + struct NineSurface9 *rt = NineSurface9(pRenderTarget); + const unsigned i = RenderTargetIndex; + + DBG("This=%p RenderTargetIndex=%u pRenderTarget=%p\n", This, + RenderTargetIndex, pRenderTarget); + + user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL); + user_assert(i != 0 || pRenderTarget, D3DERR_INVALIDCALL); + user_assert(!pRenderTarget || + rt->desc.Usage & D3DUSAGE_RENDERTARGET, D3DERR_INVALIDCALL); + + if (i == 0) { + This->state.viewport.X = 0; + This->state.viewport.Y = 0; + This->state.viewport.Width = rt->desc.Width; + This->state.viewport.Height = rt->desc.Height; + This->state.viewport.MinZ = 0.0f; + This->state.viewport.MaxZ = 1.0f; + + This->state.scissor.minx = 0; + This->state.scissor.miny = 0; + This->state.scissor.maxx = rt->desc.Width; + This->state.scissor.maxy = rt->desc.Height; + + This->state.changed.group |= NINE_STATE_VIEWPORT | NINE_STATE_SCISSOR; + } + + if (This->state.rt[i] != NineSurface9(pRenderTarget)) { + nine_bind(&This->state.rt[i], pRenderTarget); + This->state.changed.group |= NINE_STATE_FB; + } + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 **ppRenderTarget ) +{ + const unsigned i = RenderTargetIndex; + + user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL); + user_assert(ppRenderTarget, D3DERR_INVALIDCALL); + + *ppRenderTarget = (IDirect3DSurface9 *)This->state.rt[i]; + if (!This->state.rt[i]) + return D3DERR_NOTFOUND; + + NineUnknown_AddRef(NineUnknown(This->state.rt[i])); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ) +{ + DBG("This=%p pNewZStencil=%p\n", This, pNewZStencil); + + if (This->state.ds != NineSurface9(pNewZStencil)) { + nine_bind(&This->state.ds, pNewZStencil); + This->state.changed.group |= NINE_STATE_FB; + } + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 **ppZStencilSurface ) +{ + user_assert(ppZStencilSurface, D3DERR_INVALIDCALL); + + *ppZStencilSurface = (IDirect3DSurface9 *)This->state.ds; + if (!This->state.ds) + return D3DERR_NOTFOUND; + + NineUnknown_AddRef(NineUnknown(This->state.ds)); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_BeginScene( struct NineDevice9 *This ) +{ + DBG("This=%p\n", This); + user_assert(!This->in_scene, D3DERR_INVALIDCALL); + This->in_scene = TRUE; + /* Do we want to do anything else here ? */ + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_EndScene( struct NineDevice9 *This ) +{ + DBG("This=%p\n", This); + user_assert(This->in_scene, D3DERR_INVALIDCALL); + This->in_scene = FALSE; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ) +{ + struct pipe_context *pipe = This->pipe; + struct NineSurface9 *zsbuf = This->state.ds; + unsigned bufs = 0; + unsigned r, i; + union pipe_color_union rgba; + D3DRECT rect; + + DBG("This=%p Count=%u pRects=%p Flags=%x Color=%08x Z=%f Stencil=%x\n", + This, Count, pRects, Flags, Color, Z, Stencil); + + user_assert(This->state.ds || !(Flags & NINED3DCLEAR_DEPTHSTENCIL), + D3DERR_INVALIDCALL); + user_assert(!(Flags & D3DCLEAR_STENCIL) || + (zsbuf && + util_format_is_depth_and_stencil(zsbuf->base.info.format)), + D3DERR_INVALIDCALL); +#ifdef NINE_STRICT + user_assert((Count && pRects) || (!Count && !pRects), D3DERR_INVALIDCALL); +#else + user_warn((pRects && !Count) || (!pRects && Count)); + if (pRects && !Count) + return D3D_OK; + if (!pRects) + Count = 0; +#endif + + if (Flags & D3DCLEAR_TARGET) bufs |= PIPE_CLEAR_COLOR; + if (Flags & D3DCLEAR_ZBUFFER) bufs |= PIPE_CLEAR_DEPTH; + if (Flags & D3DCLEAR_STENCIL) bufs |= PIPE_CLEAR_STENCIL; + if (!bufs) + return D3D_OK; + d3dcolor_to_pipe_color_union(&rgba, Color); + + nine_update_state(This, NINE_STATE_FB); + + rect.x1 = This->state.viewport.X; + rect.y1 = This->state.viewport.Y; + rect.x2 = This->state.viewport.Width + rect.x1; + rect.y2 = This->state.viewport.Height + rect.y1; + + /* Both rectangles apply, which is weird, but that's D3D9. */ + if (This->state.rs[D3DRS_SCISSORTESTENABLE]) { + rect.x1 = MAX2(rect.x1, This->state.scissor.minx); + rect.y1 = MAX2(rect.y1, This->state.scissor.miny); + rect.x2 = MIN2(rect.x2, This->state.scissor.maxx); + rect.y2 = MIN2(rect.y2, This->state.scissor.maxy); + } + + if (Count) { + /* Maybe apps like to specify a large rect ? */ + if (pRects[0].x1 <= rect.x1 && pRects[0].x2 >= rect.x2 && + pRects[0].y1 <= rect.y1 && pRects[0].y2 >= rect.y2) { + DBG("First rect covers viewport.\n"); + Count = 0; + pRects = NULL; + } + } + + if (rect.x1 >= This->state.fb.width || rect.y1 >= This->state.fb.height) + return D3D_OK; + if (!Count && + rect.x1 == 0 && rect.x2 >= This->state.fb.width && + rect.y1 == 0 && rect.y2 >= This->state.fb.height) { + /* fast path, clears everything at once */ + DBG("fast path\n"); + pipe->clear(pipe, bufs, &rgba, Z, Stencil); + return D3D_OK; + } + rect.x2 = MIN2(rect.x2, This->state.fb.width); + rect.y2 = MIN2(rect.y2, This->state.fb.height); + + if (!Count) { + Count = 1; + pRects = ▭ + } + + for (i = 0; (i < This->state.fb.nr_cbufs); ++i) { + if (!This->state.fb.cbufs[i] || !(Flags & D3DCLEAR_TARGET)) + continue; /* save space, compiler should hoist this */ + for (r = 0; r < Count; ++r) { + /* Don't trust users to pass these in the right order. */ + unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2); + unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2); + unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2); + unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2); +#ifndef NINE_LAX + /* Drop negative rectangles (like wine expects). */ + if (pRects[r].x1 > pRects[r].x2) continue; + if (pRects[r].y1 > pRects[r].y2) continue; +#endif + + x1 = MAX2(x1, rect.x1); + y1 = MAX2(y1, rect.y1); + x2 = MIN2(x2, rect.x2); + y2 = MIN2(y2, rect.y2); + + DBG("Clearing (%u..%u)x(%u..%u)\n", x1, x2, y1, y2); + pipe->clear_render_target(pipe, This->state.fb.cbufs[i], &rgba, + x1, y1, x2 - x1, y2 - y1); + } + } + if (!(Flags & NINED3DCLEAR_DEPTHSTENCIL)) + return D3D_OK; + + bufs &= PIPE_CLEAR_DEPTHSTENCIL; + + for (r = 0; r < Count; ++r) { + unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2); + unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2); + unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2); + unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2); +#ifndef NINE_LAX + /* Drop negative rectangles. */ + if (pRects[r].x1 > pRects[r].x2) continue; + if (pRects[r].y1 > pRects[r].y2) continue; +#endif + + x1 = MIN2(x1, rect.x1); + y1 = MIN2(y1, rect.y1); + x2 = MIN2(x2, rect.x2); + y2 = MIN2(y2, rect.y2); + + pipe->clear_depth_stencil(pipe, This->state.fb.zsbuf, bufs, Z, Stencil, + x1, y1, x2 - x1, y2 - y1); + } + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + struct nine_state *state = This->update; + D3DMATRIX *M = nine_state_access_transform(state, State, TRUE); + user_assert(M, D3DERR_INVALIDCALL); + + *M = *pMatrix; + state->ff.changed.transform[State / 32] |= 1 << (State % 32); + state->changed.group |= NINE_STATE_FF; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ) +{ + D3DMATRIX *M = nine_state_access_transform(&This->state, State, FALSE); + user_assert(M, D3DERR_INVALIDCALL); + *pMatrix = *M; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_MultiplyTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + struct nine_state *state = This->update; + D3DMATRIX T; + D3DMATRIX *M = nine_state_access_transform(state, State, TRUE); + user_assert(M, D3DERR_INVALIDCALL); + + nine_d3d_matrix_matrix_mul(&T, pMatrix, M); + return NineDevice9_SetTransform(This, State, &T); +} + +HRESULT WINAPI +NineDevice9_SetViewport( struct NineDevice9 *This, + const D3DVIEWPORT9 *pViewport ) +{ + struct nine_state *state = This->update; + + DBG("X=%u Y=%u W=%u H=%u MinZ=%f MaxZ=%f\n", + pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, + pViewport->MinZ, pViewport->MaxZ); + + state->viewport = *pViewport; + state->changed.group |= NINE_STATE_VIEWPORT; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ) +{ + *pViewport = This->state.viewport; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetMaterial( struct NineDevice9 *This, + const D3DMATERIAL9 *pMaterial ) +{ + struct nine_state *state = This->update; + + DBG("This=%p pMaterial=%p\n", This, pMaterial); + if (pMaterial) + nine_dump_D3DMATERIAL9(DBG_FF, pMaterial); + + user_assert(pMaterial, E_POINTER); + + state->ff.material = *pMaterial; + state->changed.group |= NINE_STATE_FF_MATERIAL; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ) +{ + user_assert(pMaterial, E_POINTER); + *pMaterial = This->state.ff.material; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ) +{ + struct nine_state *state = This->update; + + DBG("This=%p Index=%u pLight=%p\n", This, Index, pLight); + if (pLight) + nine_dump_D3DLIGHT9(DBG_FF, pLight); + + user_assert(pLight, D3DERR_INVALIDCALL); + user_assert(pLight->Type < NINED3DLIGHT_INVALID, D3DERR_INVALIDCALL); + + user_assert(Index < NINE_MAX_LIGHTS, D3DERR_INVALIDCALL); /* sanity */ + + if (Index >= state->ff.num_lights) { + unsigned n = state->ff.num_lights; + unsigned N = Index + 1; + + state->ff.light = REALLOC(state->ff.light, n * sizeof(D3DLIGHT9), + N * sizeof(D3DLIGHT9)); + if (!state->ff.light) + return E_OUTOFMEMORY; + state->ff.num_lights = N; + + for (; n < Index; ++n) + state->ff.light[n].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; + } + state->ff.light[Index] = *pLight; + + if (pLight->Type == D3DLIGHT_SPOT && pLight->Theta >= pLight->Phi) { + DBG("Warning: clamping D3DLIGHT9.Theta\n"); + state->ff.light[Index].Theta = state->ff.light[Index].Phi; + } + if (pLight->Type != D3DLIGHT_DIRECTIONAL && + pLight->Attenuation0 == 0.0f && + pLight->Attenuation1 == 0.0f && + pLight->Attenuation2 == 0.0f) { + DBG("Warning: all D3DLIGHT9.Attenuation[i] are 0\n"); + } + + state->changed.group |= NINE_STATE_FF_LIGHTING; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ) +{ + const struct nine_state *state = &This->state; + + user_assert(pLight, D3DERR_INVALIDCALL); + user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL); + user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID, + D3DERR_INVALIDCALL); + + *pLight = state->ff.light[Index]; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ) +{ + struct nine_state *state = This->update; + unsigned i; + + DBG("This=%p Index=%u Enable=%i\n", This, Index, Enable); + + if (Index >= state->ff.num_lights || + state->ff.light[Index].Type == NINED3DLIGHT_INVALID) { + /* This should create a default light. */ + D3DLIGHT9 light; + memset(&light, 0, sizeof(light)); + light.Type = D3DLIGHT_DIRECTIONAL; + light.Diffuse.r = 1.0f; + light.Diffuse.g = 1.0f; + light.Diffuse.b = 1.0f; + light.Direction.z = 1.0f; + NineDevice9_SetLight(This, Index, &light); + } + user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL); + + for (i = 0; i < state->ff.num_lights_active; ++i) { + if (state->ff.active_light[i] == Index) + break; + } + + if (Enable) { + if (i < state->ff.num_lights_active) + return D3D_OK; + /* XXX wine thinks this should still succeed: + */ + user_assert(i < NINE_MAX_LIGHTS_ACTIVE, D3DERR_INVALIDCALL); + + state->ff.active_light[i] = Index; + state->ff.num_lights_active++; + } else { + if (i == state->ff.num_lights_active) + return D3D_OK; + --state->ff.num_lights_active; + for (; i < state->ff.num_lights_active; ++i) + state->ff.active_light[i] = state->ff.active_light[i + 1]; + } + state->changed.group |= NINE_STATE_FF_LIGHTING; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ) +{ + const struct nine_state *state = &This->state; + unsigned i; + + user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL); + user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID, + D3DERR_INVALIDCALL); + + for (i = 0; i < state->ff.num_lights_active; ++i) + if (state->ff.active_light[i] == Index) + break; + *pEnable = i != state->ff.num_lights_active; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ) +{ + struct nine_state *state = This->update; + + DBG("This=%p Index=%u pPlane=%p(%f %f %f %f)\n", This, Index, pPlane, + pPlane ? pPlane[0] : 0.0f, pPlane ? pPlane[1] : 0.0f, + pPlane ? pPlane[2] : 0.0f, pPlane ? pPlane[3] : 0.0f); + + user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL); + + memcpy(&state->clip.ucp[Index][0], pPlane, sizeof(state->clip.ucp[0])); + state->changed.ucp |= 1 << Index; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ) +{ + const struct nine_state *state = &This->state; + + user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL); + + memcpy(pPlane, &state->clip.ucp[Index][0], sizeof(state->clip.ucp[0])); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD Value ) +{ + struct nine_state *state = This->update; + + DBG("This=%p State=%u(%s) Value=%08x\n", This, + State, nine_d3drs_to_string(State), Value); + + user_assert(State < Elements(state->rs), D3DERR_INVALIDCALL); + + if (likely(state->rs[State] != Value) || unlikely(This->is_recording)) { + state->rs[State] = Value; + state->changed.rs[State / 32] |= 1 << (State % 32); + state->changed.group |= nine_render_state_group[State]; + } + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ) +{ + user_assert(State < Elements(This->state.rs), D3DERR_INVALIDCALL); + + *pValue = This->state.rs[State]; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_CreateStateBlock( struct NineDevice9 *This, + D3DSTATEBLOCKTYPE Type, + IDirect3DStateBlock9 **ppSB ) +{ + struct NineStateBlock9 *nsb; + struct nine_state *dst; + HRESULT hr; + enum nine_stateblock_type type; + unsigned s; + + DBG("This=%p Type=%u ppSB=%p\n", This, Type, ppSB); + + user_assert(Type == D3DSBT_ALL || + Type == D3DSBT_VERTEXSTATE || + Type == D3DSBT_PIXELSTATE, D3DERR_INVALIDCALL); + + switch (Type) { + case D3DSBT_VERTEXSTATE: type = NINESBT_VERTEXSTATE; break; + case D3DSBT_PIXELSTATE: type = NINESBT_PIXELSTATE; break; + default: + type = NINESBT_ALL; + break; + } + + hr = NineStateBlock9_new(This, &nsb, type); + if (FAILED(hr)) + return hr; + *ppSB = (IDirect3DStateBlock9 *)nsb; + dst = &nsb->state; + + dst->changed.group = + NINE_STATE_TEXTURE | + NINE_STATE_SAMPLER; + + if (Type == D3DSBT_ALL || Type == D3DSBT_VERTEXSTATE) { + dst->changed.group |= + NINE_STATE_FF_LIGHTING | + NINE_STATE_VS | NINE_STATE_VS_CONST | + NINE_STATE_VDECL; + /* TODO: texture/sampler state */ + memcpy(dst->changed.rs, + nine_render_states_vertex, sizeof(dst->changed.rs)); + nine_ranges_insert(&dst->changed.vs_const_f, 0, This->max_vs_const_f, + &This->range_pool); + dst->changed.vs_const_i = 0xffff; + dst->changed.vs_const_b = 0xffff; + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) + dst->changed.sampler[s] |= 1 << D3DSAMP_DMAPOFFSET; + if (This->state.ff.num_lights) { + dst->ff.num_lights = This->state.ff.num_lights; + /* zero'd -> light type won't be NINED3DLIGHT_INVALID, so + * all currently existing lights will be captured + */ + dst->ff.light = CALLOC(This->state.ff.num_lights, + sizeof(D3DLIGHT9)); + if (!dst->ff.light) { + nine_bind(ppSB, NULL); + return E_OUTOFMEMORY; + } + } + } + if (Type == D3DSBT_ALL || Type == D3DSBT_PIXELSTATE) { + dst->changed.group |= + NINE_STATE_PS | NINE_STATE_PS_CONST; + /* TODO: texture/sampler state */ + memcpy(dst->changed.rs, + nine_render_states_pixel, sizeof(dst->changed.rs)); + nine_ranges_insert(&dst->changed.ps_const_f, 0, This->max_ps_const_f, + &This->range_pool); + dst->changed.ps_const_i = 0xffff; + dst->changed.ps_const_b = 0xffff; + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) + dst->changed.sampler[s] |= 0x1ffe; + } + if (Type == D3DSBT_ALL) { + dst->changed.group |= + NINE_STATE_VIEWPORT | + NINE_STATE_SCISSOR | + NINE_STATE_RASTERIZER | + NINE_STATE_BLEND | + NINE_STATE_DSA | + NINE_STATE_IDXBUF | + NINE_STATE_MATERIAL | + NINE_STATE_BLEND_COLOR | + NINE_STATE_SAMPLE_MASK; + memset(dst->changed.rs, ~0, (D3DRS_COUNT / 32) * sizeof(uint32_t)); + dst->changed.rs[D3DRS_LAST / 32] |= (1 << (D3DRS_COUNT % 32)) - 1; + dst->changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1; + dst->changed.stream_freq = dst->changed.vtxbuf; + dst->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1; + dst->changed.texture = (1 << NINE_MAX_SAMPLERS) - 1; + } + NineStateBlock9_Capture(NineStateBlock9(*ppSB)); + + /* TODO: fixed function state */ + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_BeginStateBlock( struct NineDevice9 *This ) +{ + HRESULT hr; + + DBG("This=%p\n", This); + + user_assert(!This->record, D3DERR_INVALIDCALL); + + hr = NineStateBlock9_new(This, &This->record, NINESBT_CUSTOM); + if (FAILED(hr)) + return hr; + NineUnknown_ConvertRefToBind(NineUnknown(This->record)); + + This->update = &This->record->state; + This->is_recording = TRUE; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ) +{ + DBG("This=%p ppSB=%p\n", This, ppSB); + + user_assert(This->record, D3DERR_INVALIDCALL); + + This->update = &This->state; + This->is_recording = FALSE; + + NineUnknown_AddRef(NineUnknown(This->record)); + *ppSB = (IDirect3DStateBlock9 *)This->record; + NineUnknown_Unbind(NineUnknown(This->record)); + This->record = NULL; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ) +{ + user_assert(Stage < This->caps.MaxSimultaneousTextures || + Stage == D3DDMAPSAMPLER || + (Stage >= D3DVERTEXTEXTURESAMPLER0 && + Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + user_assert(ppTexture, D3DERR_INVALIDCALL); + + if (Stage >= D3DDMAPSAMPLER) + Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + *ppTexture = (IDirect3DBaseTexture9 *)This->state.texture[Stage]; + + if (This->state.texture[Stage]) + NineUnknown_AddRef(NineUnknown(This->state.texture[Stage])); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ) +{ + struct nine_state *state = This->update; + + DBG("This=%p Stage=%u pTexture=%p\n", This, Stage, pTexture); + + user_assert(Stage < This->caps.MaxSimultaneousTextures || + Stage == D3DDMAPSAMPLER || + (Stage >= D3DVERTEXTEXTURESAMPLER0 && + Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + + if (Stage >= D3DDMAPSAMPLER) + Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + if (!This->is_recording) { + struct NineBaseTexture9 *tex = NineBaseTexture9(pTexture); + struct NineBaseTexture9 *old = state->texture[Stage]; + if (old == tex) + return D3D_OK; + + state->samplers_shadow &= ~(1 << Stage); + if (tex) { + state->samplers_shadow |= tex->shadow << Stage; + + if ((tex->dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list)) + list_add(&tex->list, &This->update_textures); + + tex->bind_count++; + } + if (old) + old->bind_count--; + } + nine_bind(&state->texture[Stage], pTexture); + + state->changed.texture |= 1 << Stage; + state->changed.group |= NINE_STATE_TEXTURE; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ) +{ + const struct nine_state *state = &This->state; + + user_assert(Stage < Elements(state->ff.tex_stage), D3DERR_INVALIDCALL); + user_assert(Type < Elements(state->ff.tex_stage[0]), D3DERR_INVALIDCALL); + + *pValue = state->ff.tex_stage[Stage][Type]; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value ) +{ + struct nine_state *state = This->update; + + DBG("Stage=%u Type=%u Value=%08x\n", Stage, Type, Value); + nine_dump_D3DTSS_value(DBG_FF, Type, Value); + + user_assert(Stage < Elements(state->ff.tex_stage), D3DERR_INVALIDCALL); + user_assert(Type < Elements(state->ff.tex_stage[0]), D3DERR_INVALIDCALL); + + state->ff.tex_stage[Stage][Type] = Value; + + state->changed.group |= NINE_STATE_FF_PSSTAGES; + state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ) +{ + user_assert(Sampler < This->caps.MaxSimultaneousTextures || + Sampler == D3DDMAPSAMPLER || + (Sampler >= D3DVERTEXTEXTURESAMPLER0 && + Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + + if (Sampler >= D3DDMAPSAMPLER) + Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + *pValue = This->state.samp[Sampler][Type]; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value ) +{ + struct nine_state *state = This->update; + + DBG("This=%p Sampler=%u Type=%s Value=%08x\n", This, + Sampler, nine_D3DSAMP_to_str(Type), Value); + + user_assert(Sampler < This->caps.MaxSimultaneousTextures || + Sampler == D3DDMAPSAMPLER || + (Sampler >= D3DVERTEXTEXTURESAMPLER0 && + Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL); + + if (Sampler >= D3DDMAPSAMPLER) + Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; + + state->samp[Sampler][Type] = Value; + state->changed.group |= NINE_STATE_SAMPLER; + state->changed.sampler[Sampler] |= 1 << Type; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_ValidateDevice( struct NineDevice9 *This, + DWORD *pNumPasses ) +{ + const struct nine_state *state = &This->state; + unsigned i; + unsigned w = 0, h = 0; + + DBG("This=%p pNumPasses=%p\n", This, pNumPasses); + + for (i = 0; i < Elements(state->samp); ++i) { + if (state->samp[i][D3DSAMP_MINFILTER] == D3DTEXF_NONE || + state->samp[i][D3DSAMP_MAGFILTER] == D3DTEXF_NONE) + return D3DERR_UNSUPPORTEDTEXTUREFILTER; + } + + for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) { + if (!state->rt[i]) + continue; + if (w == 0) { + w = state->rt[i]->desc.Width; + h = state->rt[i]->desc.Height; + } else + if (state->rt[i]->desc.Width != w || state->rt[i]->desc.Height != h) { + return D3DERR_CONFLICTINGRENDERSTATE; + } + } + if (state->ds && + (state->rs[D3DRS_ZENABLE] || state->rs[D3DRS_STENCILENABLE])) { + if (w != 0 && + (state->ds->desc.Width != w || state->ds->desc.Height != h)) + return D3DERR_CONFLICTINGRENDERSTATE; + } + + if (pNumPasses) + *pNumPasses = 1; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ) +{ + STUB(D3D_OK); /* like wine */ +} + +HRESULT WINAPI +NineDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ) +{ + STUB(D3D_OK); /* like wine */ +} + +HRESULT WINAPI +NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ) +{ + struct nine_state *state = This->update; + + DBG("x=(%u..%u) y=(%u..%u)\n", + pRect->left, pRect->top, pRect->right, pRect->bottom); + + state->scissor.minx = pRect->left; + state->scissor.miny = pRect->top; + state->scissor.maxx = pRect->right; + state->scissor.maxy = pRect->bottom; + + state->changed.group |= NINE_STATE_SCISSOR; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ) +{ + pRect->left = This->state.scissor.minx; + pRect->top = This->state.scissor.miny; + pRect->right = This->state.scissor.maxx; + pRect->bottom = This->state.scissor.maxy; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ) +{ + STUB(D3DERR_INVALIDCALL); +} + +BOOL WINAPI +NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ) +{ + return !!(This->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING); +} + +HRESULT WINAPI +NineDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ) +{ + STUB(D3DERR_INVALIDCALL); +} + +float WINAPI +NineDevice9_GetNPatchMode( struct NineDevice9 *This ) +{ + STUB(0); +} + +static INLINE void +init_draw_info(struct pipe_draw_info *info, + struct NineDevice9 *dev, D3DPRIMITIVETYPE type, UINT count) +{ + info->mode = d3dprimitivetype_to_pipe_prim(type); + info->count = prim_count_to_vertex_count(type, count); + info->start_instance = 0; + info->instance_count = 1; + if (dev->state.stream_instancedata_mask & dev->state.stream_usage_mask) + info->instance_count = MAX2(dev->state.stream_freq[0] & 0x7FFFFF, 1); + info->primitive_restart = FALSE; + info->restart_index = 0; + info->count_from_stream_output = NULL; + info->indirect = NULL; +} + +HRESULT WINAPI +NineDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ) +{ + struct pipe_draw_info info; + + DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n", + This, PrimitiveType, StartVertex, PrimitiveCount); + + nine_update_state(This, ~0); + + init_draw_info(&info, This, PrimitiveType, PrimitiveCount); + info.indexed = FALSE; + info.start = StartVertex; + info.index_bias = 0; + info.min_index = info.start; + info.max_index = info.count - 1; + + This->pipe->draw_vbo(This->pipe, &info); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT StartIndex, + UINT PrimitiveCount ) +{ + struct pipe_draw_info info; + + DBG("iface %p, PrimitiveType %u, BaseVertexIndex %u, MinVertexIndex %u " + "NumVertices %u, StartIndex %u, PrimitiveCount %u\n", + This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, + StartIndex, PrimitiveCount); + + user_assert(This->state.idxbuf, D3DERR_INVALIDCALL); + user_assert(This->state.vdecl, D3DERR_INVALIDCALL); + + nine_update_state(This, ~0); + + init_draw_info(&info, This, PrimitiveType, PrimitiveCount); + info.indexed = TRUE; + info.start = StartIndex; + info.index_bias = BaseVertexIndex; + /* These don't include index bias: */ + info.min_index = MinVertexIndex; + info.max_index = MinVertexIndex + NumVertices - 1; + + This->pipe->draw_vbo(This->pipe, &info); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + struct pipe_vertex_buffer vtxbuf; + struct pipe_draw_info info; + + DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n", + This, PrimitiveType, PrimitiveCount, + pVertexStreamZeroData, VertexStreamZeroStride); + + user_assert(pVertexStreamZeroData && VertexStreamZeroStride, + D3DERR_INVALIDCALL); + + nine_update_state(This, ~0); + + init_draw_info(&info, This, PrimitiveType, PrimitiveCount); + info.indexed = FALSE; + info.start = 0; + info.index_bias = 0; + info.min_index = 0; + info.max_index = info.count - 1; + + vtxbuf.stride = VertexStreamZeroStride; + vtxbuf.buffer_offset = 0; + vtxbuf.buffer = NULL; + vtxbuf.user_buffer = pVertexStreamZeroData; + + if (!This->driver_caps.user_vbufs) + u_upload_data(This->upload, + 0, + (info.max_index + 1) * VertexStreamZeroStride, /* XXX */ + vtxbuf.user_buffer, + &vtxbuf.buffer_offset, + &vtxbuf.buffer); + + This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vtxbuf); + + This->pipe->draw_vbo(This->pipe, &info); + + NineDevice9_PauseRecording(This); + NineDevice9_SetStreamSource(This, 0, NULL, 0, 0); + NineDevice9_ResumeRecording(This); + + pipe_resource_reference(&vtxbuf.buffer, NULL); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex, + UINT NumVertices, + UINT PrimitiveCount, + const void *pIndexData, + D3DFORMAT IndexDataFormat, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + struct pipe_draw_info info; + struct pipe_vertex_buffer vbuf; + struct pipe_index_buffer ibuf; + + DBG("iface %p, PrimitiveType %u, MinVertexIndex %u, NumVertices %u " + "PrimitiveCount %u, pIndexData %p, IndexDataFormat %u " + "pVertexStreamZeroData %p, VertexStreamZeroStride %u\n", + This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, + pIndexData, IndexDataFormat, + pVertexStreamZeroData, VertexStreamZeroStride); + + user_assert(pIndexData && pVertexStreamZeroData, D3DERR_INVALIDCALL); + user_assert(VertexStreamZeroStride, D3DERR_INVALIDCALL); + user_assert(IndexDataFormat == D3DFMT_INDEX16 || + IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL); + + nine_update_state(This, ~0); + + init_draw_info(&info, This, PrimitiveType, PrimitiveCount); + info.indexed = TRUE; + info.start = 0; + info.index_bias = 0; + info.min_index = MinVertexIndex; + info.max_index = MinVertexIndex + NumVertices - 1; + + vbuf.stride = VertexStreamZeroStride; + vbuf.buffer_offset = 0; + vbuf.buffer = NULL; + vbuf.user_buffer = pVertexStreamZeroData; + + ibuf.index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4; + ibuf.offset = 0; + ibuf.buffer = NULL; + ibuf.user_buffer = pIndexData; + + if (!This->driver_caps.user_vbufs) { + const unsigned base = info.min_index * VertexStreamZeroStride; + u_upload_data(This->upload, + base, + (info.max_index - + info.min_index + 1) * VertexStreamZeroStride, /* XXX */ + (const uint8_t *)vbuf.user_buffer + base, + &vbuf.buffer_offset, + &vbuf.buffer); + /* Won't be used: */ + vbuf.buffer_offset -= base; + } + if (!This->driver_caps.user_ibufs) + u_upload_data(This->upload, + 0, + info.count * ibuf.index_size, + ibuf.user_buffer, + &ibuf.offset, + &ibuf.buffer); + + This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vbuf); + This->pipe->set_index_buffer(This->pipe, &ibuf); + + This->pipe->draw_vbo(This->pipe, &info); + + pipe_resource_reference(&vbuf.buffer, NULL); + pipe_resource_reference(&ibuf.buffer, NULL); + + NineDevice9_PauseRecording(This); + NineDevice9_SetIndices(This, NULL); + NineDevice9_SetStreamSource(This, 0, NULL, 0, 0); + NineDevice9_ResumeRecording(This); + + return D3D_OK; +} + +/* TODO: Write to pDestBuffer directly if vertex declaration contains + * only f32 formats. + */ +HRESULT WINAPI +NineDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ) +{ + struct pipe_screen *screen = This->screen; + struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pVertexDecl); + struct NineVertexShader9 *vs; + struct pipe_resource *resource; + struct pipe_stream_output_target *target; + struct pipe_draw_info draw; + HRESULT hr; + unsigned buffer_offset, buffer_size; + + if (!screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS)) + STUB(D3DERR_INVALIDCALL); + + nine_update_state(This, ~0); + + /* TODO: Create shader with stream output. */ + STUB(D3DERR_INVALIDCALL); + struct NineVertexBuffer9 *dst = NineVertexBuffer9(pDestBuffer); + + vs = This->state.vs ? This->state.vs : This->ff.vs; + + buffer_size = VertexCount * vs->so->stride[0]; + if (1) { + struct pipe_resource templ; + + templ.target = PIPE_BUFFER; + templ.format = PIPE_FORMAT_R8_UNORM; + templ.width0 = buffer_size; + templ.flags = 0; + templ.bind = PIPE_BIND_STREAM_OUTPUT; + templ.usage = PIPE_USAGE_STREAM; + templ.height0 = templ.depth0 = templ.array_size = 1; + templ.last_level = templ.nr_samples = 0; + + resource = This->screen->resource_create(This->screen, &templ); + if (!resource) + return E_OUTOFMEMORY; + buffer_offset = 0; + } else { + /* SO matches vertex declaration */ + resource = dst->base.resource; + buffer_offset = DestIndex * vs->so->stride[0]; + } + target = This->pipe->create_stream_output_target(This->pipe, resource, + buffer_offset, + buffer_size); + if (!target) { + pipe_resource_reference(&resource, NULL); + return D3DERR_DRIVERINTERNALERROR; + } + + if (!vdecl) { + hr = NineVertexDeclaration9_new_from_fvf(This, dst->desc.FVF, &vdecl); + if (FAILED(hr)) + goto out; + } + + init_draw_info(&draw, This, D3DPT_POINTLIST, VertexCount); + draw.instance_count = 1; + draw.indexed = FALSE; + draw.start = SrcStartIndex; + draw.index_bias = 0; + draw.min_index = SrcStartIndex; + draw.max_index = SrcStartIndex + VertexCount - 1; + + This->pipe->set_stream_output_targets(This->pipe, 1, &target, 0); + This->pipe->draw_vbo(This->pipe, &draw); + This->pipe->set_stream_output_targets(This->pipe, 0, NULL, 0); + This->pipe->stream_output_target_destroy(This->pipe, target); + + hr = NineVertexDeclaration9_ConvertStreamOutput(vdecl, + dst, DestIndex, VertexCount, + resource, vs->so); +out: + pipe_resource_reference(&resource, NULL); + if (!pVertexDecl) + NineUnknown_Release(NineUnknown(vdecl)); + return hr; +} + +HRESULT WINAPI +NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + struct NineVertexDeclaration9 *vdecl; + + HRESULT hr = NineVertexDeclaration9_new(This, pVertexElements, &vdecl); + if (SUCCEEDED(hr)) + *ppDecl = (IDirect3DVertexDeclaration9 *)vdecl; + + return hr; +} + +HRESULT WINAPI +NineDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ) +{ + struct nine_state *state = This->update; + + DBG("This=%p pDecl=%p\n", This, pDecl); + + if (likely(!This->is_recording) && state->vdecl == NineVertexDeclaration9(pDecl)) + return D3D_OK; + nine_bind(&state->vdecl, pDecl); + + state->changed.group |= NINE_STATE_VDECL; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + user_assert(ppDecl, D3DERR_INVALIDCALL); + + *ppDecl = (IDirect3DVertexDeclaration9 *)This->state.vdecl; + if (*ppDecl) + NineUnknown_AddRef(NineUnknown(*ppDecl)); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetFVF( struct NineDevice9 *This, + DWORD FVF ) +{ + struct NineVertexDeclaration9 *vdecl; + HRESULT hr; + + DBG("FVF = %08x\n", FVF); + if (!FVF) + return D3D_OK; /* like wine */ + + vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF); + if (!vdecl) { + hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl); + if (FAILED(hr)) + return hr; + vdecl->fvf = FVF; + util_hash_table_set(This->ff.ht_fvf, &vdecl->fvf, vdecl); + NineUnknown_ConvertRefToBind(NineUnknown(vdecl)); + } + return NineDevice9_SetVertexDeclaration( + This, (IDirect3DVertexDeclaration9 *)vdecl); +} + +HRESULT WINAPI +NineDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ) +{ + *pFVF = This->state.vdecl ? This->state.vdecl->fvf : 0; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ) +{ + struct NineVertexShader9 *vs; + HRESULT hr; + + hr = NineVertexShader9_new(This, &vs, pFunction, NULL); + if (FAILED(hr)) + return hr; + *ppShader = (IDirect3DVertexShader9 *)vs; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ) +{ + struct nine_state *state = This->update; + + DBG("This=%p pShader=%p\n", This, pShader); + + nine_bind(&state->vs, pShader); + + state->changed.group |= NINE_STATE_VS; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ) +{ + user_assert(ppShader, D3DERR_INVALIDCALL); + nine_reference_set(ppShader, This->state.vs); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n", + This, StartRegister, pConstantData, Vector4fCount); + + user_assert(StartRegister < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL); + + if (!Vector4fCount) + return D3D_OK; + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->vs_const_f[StartRegister * 4], + pConstantData, + Vector4fCount * 4 * sizeof(state->vs_const_f[0])); + + nine_ranges_insert(&state->changed.vs_const_f, + StartRegister, StartRegister + Vector4fCount, + &This->range_pool); + + state->changed.group |= NINE_STATE_VS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->vs_const_f[StartRegister * 4], + Vector4fCount * 4 * sizeof(state->vs_const_f[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n", + This, StartRegister, pConstantData, Vector4iCount); + + user_assert(StartRegister < NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->vs_const_i[StartRegister][0], + pConstantData, + Vector4iCount * sizeof(state->vs_const_i[0])); + + state->changed.vs_const_i |= ((1 << Vector4iCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_VS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->vs_const_i[StartRegister][0], + Vector4iCount * sizeof(state->vs_const_i[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n", + This, StartRegister, pConstantData, BoolCount); + + user_assert(StartRegister < NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->vs_const_b[StartRegister], + pConstantData, + BoolCount * sizeof(state->vs_const_b[0])); + + state->changed.vs_const_b |= ((1 << BoolCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_VS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->vs_const_b[StartRegister], + BoolCount * sizeof(state->vs_const_b[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ) +{ + struct nine_state *state = This->update; + struct NineVertexBuffer9 *pVBuf9 = NineVertexBuffer9(pStreamData); + const unsigned i = StreamNumber; + + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + user_assert(Stride <= This->caps.MaxStreamStride, D3DERR_INVALIDCALL); + + if (likely(!This->is_recording)) { + if (state->stream[i] == NineVertexBuffer9(pStreamData) && + state->vtxbuf[i].stride == Stride && + state->vtxbuf[i].buffer_offset == OffsetInBytes) + return D3D_OK; + } + nine_bind(&state->stream[i], pStreamData); + + state->changed.vtxbuf |= 1 << StreamNumber; + + if (pStreamData) { + state->vtxbuf[i].stride = Stride; + state->vtxbuf[i].buffer_offset = OffsetInBytes; + } + state->vtxbuf[i].buffer = pStreamData ? pVBuf9->base.resource : NULL; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 **ppStreamData, + UINT *pOffsetInBytes, + UINT *pStride ) +{ + const struct nine_state *state = &This->state; + const unsigned i = StreamNumber; + + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + user_assert(ppStreamData, D3DERR_INVALIDCALL); + + nine_reference_set(ppStreamData, state->stream[i]); + *pStride = state->vtxbuf[i].stride; + *pOffsetInBytes = state->vtxbuf[i].buffer_offset; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT Setting ) +{ + struct nine_state *state = This->update; + /* const UINT freq = Setting & 0x7FFFFF; */ + + DBG("This=%p StreamNumber=%u FrequencyParameter=0x%x\n", This, + StreamNumber, Setting); + + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + user_assert(StreamNumber != 0 || !(Setting & D3DSTREAMSOURCE_INSTANCEDATA), + D3DERR_INVALIDCALL); + user_assert(!((Setting & D3DSTREAMSOURCE_INSTANCEDATA) && + (Setting & D3DSTREAMSOURCE_INDEXEDDATA)), D3DERR_INVALIDCALL); + user_assert(Setting, D3DERR_INVALIDCALL); + + state->stream_freq[StreamNumber] = Setting; + + if (Setting & D3DSTREAMSOURCE_INSTANCEDATA) + state->stream_instancedata_mask |= 1 << StreamNumber; + else + state->stream_instancedata_mask &= ~(1 << StreamNumber); + + state->changed.stream_freq |= 1 << StreamNumber; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ) +{ + user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL); + *pSetting = This->state.stream_freq[StreamNumber]; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ) +{ + struct nine_state *state = This->update; + + if (likely(!This->is_recording)) + if (state->idxbuf == NineIndexBuffer9(pIndexData)) + return D3D_OK; + nine_bind(&state->idxbuf, pIndexData); + + state->changed.group |= NINE_STATE_IDXBUF; + + return D3D_OK; +} + +/* XXX: wine/d3d9 doesn't have pBaseVertexIndex, and it doesn't make sense + * here because it's an argument passed to the Draw calls. + */ +HRESULT WINAPI +NineDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData /*, + UINT *pBaseVertexIndex */ ) +{ + user_assert(ppIndexData, D3DERR_INVALIDCALL); + nine_reference_set(ppIndexData, This->state.idxbuf); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ) +{ + struct NinePixelShader9 *ps; + HRESULT hr; + + hr = NinePixelShader9_new(This, &ps, pFunction, NULL); + if (FAILED(hr)) + return hr; + *ppShader = (IDirect3DPixelShader9 *)ps; + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ) +{ + struct nine_state *state = This->update; + + DBG("This=%p pShader=%p\n", This, pShader); + + nine_bind(&state->ps, pShader); + + state->changed.group |= NINE_STATE_PS; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ) +{ + user_assert(ppShader, D3DERR_INVALIDCALL); + nine_reference_set(ppShader, This->state.ps); + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n", + This, StartRegister, pConstantData, Vector4fCount); + + user_assert(StartRegister < NINE_MAX_CONST_F, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F, D3DERR_INVALIDCALL); + + if (!Vector4fCount) + return D3D_OK; + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->ps_const_f[StartRegister * 4], + pConstantData, + Vector4fCount * 4 * sizeof(state->ps_const_f[0])); + + nine_ranges_insert(&state->changed.ps_const_f, + StartRegister, StartRegister + Vector4fCount, + &This->range_pool); + + state->changed.group |= NINE_STATE_PS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < NINE_MAX_CONST_F, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->ps_const_f[StartRegister * 4], + Vector4fCount * 4 * sizeof(state->ps_const_f[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n", + This, StartRegister, pConstantData, Vector4iCount); + + user_assert(StartRegister < NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->ps_const_i[StartRegister][0], + pConstantData, + Vector4iCount * sizeof(state->ps_const_i[0])); + + state->changed.ps_const_i |= ((1 << Vector4iCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_PS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->ps_const_i[StartRegister][0], + Vector4iCount * sizeof(state->ps_const_i[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + struct nine_state *state = This->update; + + DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n", + This, StartRegister, pConstantData, BoolCount); + + user_assert(StartRegister < NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(&state->ps_const_b[StartRegister], + pConstantData, + BoolCount * sizeof(state->ps_const_b[0])); + + state->changed.ps_const_b |= ((1 << BoolCount) - 1) << StartRegister; + state->changed.group |= NINE_STATE_PS_CONST; + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + const struct nine_state *state = &This->state; + + user_assert(StartRegister < NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); + user_assert(pConstantData, D3DERR_INVALIDCALL); + + memcpy(pConstantData, + &state->ps_const_b[StartRegister], + BoolCount * sizeof(state->ps_const_b[0])); + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ) +{ + struct NineQuery9 *query; + HRESULT hr; + + if (!ppQuery) + return nine_is_query_supported(Type); + + hr = NineQuery9_new(This, &query, Type); + if (FAILED(hr)) + return hr; + *ppQuery = (IDirect3DQuery9 *)query; + return D3D_OK; +} + +IDirect3DDevice9Vtbl NineDevice9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineDevice9_TestCooperativeLevel, + (void *)NineDevice9_GetAvailableTextureMem, + (void *)NineDevice9_EvictManagedResources, + (void *)NineDevice9_GetDirect3D, + (void *)NineDevice9_GetDeviceCaps, + (void *)NineDevice9_GetDisplayMode, + (void *)NineDevice9_GetCreationParameters, + (void *)NineDevice9_SetCursorProperties, + (void *)NineDevice9_SetCursorPosition, + (void *)NineDevice9_ShowCursor, + (void *)NineDevice9_CreateAdditionalSwapChain, + (void *)NineDevice9_GetSwapChain, + (void *)NineDevice9_GetNumberOfSwapChains, + (void *)NineDevice9_Reset, + (void *)NineDevice9_Present, + (void *)NineDevice9_GetBackBuffer, + (void *)NineDevice9_GetRasterStatus, + (void *)NineDevice9_SetDialogBoxMode, + (void *)NineDevice9_SetGammaRamp, + (void *)NineDevice9_GetGammaRamp, + (void *)NineDevice9_CreateTexture, + (void *)NineDevice9_CreateVolumeTexture, + (void *)NineDevice9_CreateCubeTexture, + (void *)NineDevice9_CreateVertexBuffer, + (void *)NineDevice9_CreateIndexBuffer, + (void *)NineDevice9_CreateRenderTarget, + (void *)NineDevice9_CreateDepthStencilSurface, + (void *)NineDevice9_UpdateSurface, + (void *)NineDevice9_UpdateTexture, + (void *)NineDevice9_GetRenderTargetData, + (void *)NineDevice9_GetFrontBufferData, + (void *)NineDevice9_StretchRect, + (void *)NineDevice9_ColorFill, + (void *)NineDevice9_CreateOffscreenPlainSurface, + (void *)NineDevice9_SetRenderTarget, + (void *)NineDevice9_GetRenderTarget, + (void *)NineDevice9_SetDepthStencilSurface, + (void *)NineDevice9_GetDepthStencilSurface, + (void *)NineDevice9_BeginScene, + (void *)NineDevice9_EndScene, + (void *)NineDevice9_Clear, + (void *)NineDevice9_SetTransform, + (void *)NineDevice9_GetTransform, + (void *)NineDevice9_MultiplyTransform, + (void *)NineDevice9_SetViewport, + (void *)NineDevice9_GetViewport, + (void *)NineDevice9_SetMaterial, + (void *)NineDevice9_GetMaterial, + (void *)NineDevice9_SetLight, + (void *)NineDevice9_GetLight, + (void *)NineDevice9_LightEnable, + (void *)NineDevice9_GetLightEnable, + (void *)NineDevice9_SetClipPlane, + (void *)NineDevice9_GetClipPlane, + (void *)NineDevice9_SetRenderState, + (void *)NineDevice9_GetRenderState, + (void *)NineDevice9_CreateStateBlock, + (void *)NineDevice9_BeginStateBlock, + (void *)NineDevice9_EndStateBlock, + (void *)NineDevice9_SetClipStatus, + (void *)NineDevice9_GetClipStatus, + (void *)NineDevice9_GetTexture, + (void *)NineDevice9_SetTexture, + (void *)NineDevice9_GetTextureStageState, + (void *)NineDevice9_SetTextureStageState, + (void *)NineDevice9_GetSamplerState, + (void *)NineDevice9_SetSamplerState, + (void *)NineDevice9_ValidateDevice, + (void *)NineDevice9_SetPaletteEntries, + (void *)NineDevice9_GetPaletteEntries, + (void *)NineDevice9_SetCurrentTexturePalette, + (void *)NineDevice9_GetCurrentTexturePalette, + (void *)NineDevice9_SetScissorRect, + (void *)NineDevice9_GetScissorRect, + (void *)NineDevice9_SetSoftwareVertexProcessing, + (void *)NineDevice9_GetSoftwareVertexProcessing, + (void *)NineDevice9_SetNPatchMode, + (void *)NineDevice9_GetNPatchMode, + (void *)NineDevice9_DrawPrimitive, + (void *)NineDevice9_DrawIndexedPrimitive, + (void *)NineDevice9_DrawPrimitiveUP, + (void *)NineDevice9_DrawIndexedPrimitiveUP, + (void *)NineDevice9_ProcessVertices, + (void *)NineDevice9_CreateVertexDeclaration, + (void *)NineDevice9_SetVertexDeclaration, + (void *)NineDevice9_GetVertexDeclaration, + (void *)NineDevice9_SetFVF, + (void *)NineDevice9_GetFVF, + (void *)NineDevice9_CreateVertexShader, + (void *)NineDevice9_SetVertexShader, + (void *)NineDevice9_GetVertexShader, + (void *)NineDevice9_SetVertexShaderConstantF, + (void *)NineDevice9_GetVertexShaderConstantF, + (void *)NineDevice9_SetVertexShaderConstantI, + (void *)NineDevice9_GetVertexShaderConstantI, + (void *)NineDevice9_SetVertexShaderConstantB, + (void *)NineDevice9_GetVertexShaderConstantB, + (void *)NineDevice9_SetStreamSource, + (void *)NineDevice9_GetStreamSource, + (void *)NineDevice9_SetStreamSourceFreq, + (void *)NineDevice9_GetStreamSourceFreq, + (void *)NineDevice9_SetIndices, + (void *)NineDevice9_GetIndices, + (void *)NineDevice9_CreatePixelShader, + (void *)NineDevice9_SetPixelShader, + (void *)NineDevice9_GetPixelShader, + (void *)NineDevice9_SetPixelShaderConstantF, + (void *)NineDevice9_GetPixelShaderConstantF, + (void *)NineDevice9_SetPixelShaderConstantI, + (void *)NineDevice9_GetPixelShaderConstantI, + (void *)NineDevice9_SetPixelShaderConstantB, + (void *)NineDevice9_GetPixelShaderConstantB, + (void *)NineDevice9_DrawRectPatch, + (void *)NineDevice9_DrawTriPatch, + (void *)NineDevice9_DeletePatch, + (void *)NineDevice9_CreateQuery +}; + +static const GUID *NineDevice9_IIDs[] = { + &IID_IDirect3DDevice9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineDevice9_new( struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX, + struct NineDevice9 **ppOut ) +{ + BOOL lock; + lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED); + + NINE_NEW(Device9, ppOut, lock, /* args */ + pScreen, pCreationParameters, pCaps, + pPresentationParameters, pD3D9, pPresentationGroup, pCTX); +} diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h new file mode 100644 index 00000000000..9dc248e64fb --- /dev/null +++ b/src/gallium/state_trackers/nine/device9.h @@ -0,0 +1,801 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_DEVICE9_H_ +#define _NINE_DEVICE9_H_ + +#include "d3dadapter/d3dadapter9.h" + +#include "iunknown.h" +#include "adapter9.h" + +#include "nine_helpers.h" +#include "nine_state.h" + +struct gen_mipmap_state; +struct util_hash_table; +struct pipe_screen; +struct pipe_context; +struct cso_context; +struct hud_context; +struct u_upload_mgr; + +struct NineSwapChain9; +struct NineStateBlock9; + +#include "util/u_double_list.h" + +struct NineDevice9 +{ + struct NineUnknown base; + boolean ex; + D3DDISPLAYMODEEX *pFullscreenDisplayMode; + + /* G3D context */ + struct pipe_screen *screen; + struct pipe_context *pipe; + struct cso_context *cso; + + /* creation parameters */ + D3DCAPS9 caps; + D3DDEVICE_CREATION_PARAMETERS params; + IDirect3D9 *d3d9; + + /* swapchain stuff */ + ID3DPresentGroup *present; + struct NineSwapChain9 **swapchains; + unsigned nswapchains; + + struct NineStateBlock9 *record; + struct nine_state *update; /* state to update (&state / &record->state) */ + struct nine_state state; /* device state */ + + struct list_head update_textures; + + boolean is_recording; + boolean in_scene; + + boolean prefer_user_constbuf; + + struct pipe_resource *constbuf_vs; + struct pipe_resource *constbuf_ps; + uint16_t max_vs_const_f; + uint16_t max_ps_const_f; + uint32_t vs_bool_true; + uint32_t ps_bool_true; + + struct gen_mipmap_state *gen_mipmap; + + struct { + struct util_hash_table *ht_vs; + struct util_hash_table *ht_ps; + struct NineVertexShader9 *vs; + struct NinePixelShader9 *ps; + unsigned num_vs; + unsigned num_ps; + float *vs_const; + float *ps_const; + + struct util_hash_table *ht_fvf; + } ff; + + struct { + struct pipe_resource *image; + unsigned w; + unsigned h; + POINT hotspot; /* -1, -1 if no cursor image set */ + POINT pos; + BOOL visible; + boolean software; + } cursor; + + struct { + boolean user_vbufs; + boolean user_ibufs; + boolean window_space_position_support; + } driver_caps; + + struct u_upload_mgr *upload; + + struct nine_range_pool range_pool; + + struct hud_context *hud; /* NULL if hud is disabled */ +}; +static INLINE struct NineDevice9 * +NineDevice9( void *data ) +{ + return (struct NineDevice9 *)data; +} + +HRESULT +NineDevice9_new( struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX, + struct NineDevice9 **ppOut ); + +HRESULT +NineDevice9_ctor( struct NineDevice9 *This, + struct NineUnknownParams *pParams, + struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3D9 *pD3D9, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX ); + +void +NineDevice9_dtor( struct NineDevice9 *This ); + +/*** Nine private ***/ + +struct pipe_screen * +NineDevice9_GetScreen( struct NineDevice9 *This ); + +struct pipe_context * +NineDevice9_GetPipe( struct NineDevice9 *This ); + +struct cso_context * +NineDevice9_GetCSO( struct NineDevice9 *This ); + +const D3DCAPS9 * +NineDevice9_GetCaps( struct NineDevice9 *This ); + +/* Mask: 0x1 = constant buffers, 0x2 = stipple */ +void +NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask ); + +/*** Direct3D public ***/ + +HRESULT WINAPI +NineDevice9_TestCooperativeLevel( struct NineDevice9 *This ); + +UINT WINAPI +NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_EvictManagedResources( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_GetDirect3D( struct NineDevice9 *This, + IDirect3D9 **ppD3D9 ); + +HRESULT WINAPI +NineDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ); + +HRESULT WINAPI +NineDevice9_GetDisplayMode( struct NineDevice9 *This, + UINT iSwapChain, + D3DDISPLAYMODE *pMode ); + +HRESULT WINAPI +NineDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ); + +HRESULT WINAPI +NineDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ); + +void WINAPI +NineDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ); + +BOOL WINAPI +NineDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ); + +HRESULT WINAPI +NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ); + +HRESULT WINAPI +NineDevice9_GetSwapChain( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSwapChain9 **pSwapChain ); + +UINT WINAPI +NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + +HRESULT WINAPI +NineDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ); + +HRESULT WINAPI +NineDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ); + +HRESULT WINAPI +NineDevice9_GetRasterStatus( struct NineDevice9 *This, + UINT iSwapChain, + D3DRASTER_STATUS *pRasterStatus ); + +HRESULT WINAPI +NineDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ); + +void WINAPI +NineDevice9_SetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + DWORD Flags, + const D3DGAMMARAMP *pRamp ); + +void WINAPI +NineDevice9_GetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + D3DGAMMARAMP *pRamp ); + +HRESULT WINAPI +NineDevice9_CreateTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DTexture9 **ppTexture, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateVolumeTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Depth, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DVolumeTexture9 **ppVolumeTexture, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateCubeTexture( struct NineDevice9 *This, + UINT EdgeLength, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DCubeTexture9 **ppCubeTexture, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateVertexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + DWORD FVF, + D3DPOOL Pool, + IDirect3DVertexBuffer9 **ppVertexBuffer, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateIndexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DIndexBuffer9 **ppIndexBuffer, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateRenderTarget( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_UpdateSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestinationSurface, + const POINT *pDestPoint ); + +HRESULT WINAPI +NineDevice9_UpdateTexture( struct NineDevice9 *This, + IDirect3DBaseTexture9 *pSourceTexture, + IDirect3DBaseTexture9 *pDestinationTexture ); + +HRESULT WINAPI +NineDevice9_GetRenderTargetData( struct NineDevice9 *This, + IDirect3DSurface9 *pRenderTarget, + IDirect3DSurface9 *pDestSurface ); + +HRESULT WINAPI +NineDevice9_GetFrontBufferData( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSurface9 *pDestSurface ); + +HRESULT WINAPI +NineDevice9_StretchRect( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestSurface, + const RECT *pDestRect, + D3DTEXTUREFILTERTYPE Filter ); + +HRESULT WINAPI +NineDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ); + +HRESULT WINAPI +NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineDevice9_SetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 *pRenderTarget ); + +HRESULT WINAPI +NineDevice9_GetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 **ppRenderTarget ); + +HRESULT WINAPI +NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ); + +HRESULT WINAPI +NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 **ppZStencilSurface ); + +HRESULT WINAPI +NineDevice9_BeginScene( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_EndScene( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ); + +HRESULT WINAPI +NineDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ); + +HRESULT WINAPI +NineDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ); + +HRESULT WINAPI +NineDevice9_MultiplyTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ); + +HRESULT WINAPI +NineDevice9_SetViewport( struct NineDevice9 *This, + const D3DVIEWPORT9 *pViewport ); + +HRESULT WINAPI +NineDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ); + +HRESULT WINAPI +NineDevice9_SetMaterial( struct NineDevice9 *This, + const D3DMATERIAL9 *pMaterial ); + +HRESULT WINAPI +NineDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ); + +HRESULT WINAPI +NineDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ); + +HRESULT WINAPI +NineDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ); + +HRESULT WINAPI +NineDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ); + +HRESULT WINAPI +NineDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ); + +HRESULT WINAPI +NineDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ); + +HRESULT WINAPI +NineDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ); + +HRESULT WINAPI +NineDevice9_SetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD Value ); + +HRESULT WINAPI +NineDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ); + +HRESULT WINAPI +NineDevice9_CreateStateBlock( struct NineDevice9 *This, + D3DSTATEBLOCKTYPE Type, + IDirect3DStateBlock9 **ppSB ); + +HRESULT WINAPI +NineDevice9_BeginStateBlock( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ); + +HRESULT WINAPI +NineDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ); + +HRESULT WINAPI +NineDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ); + +HRESULT WINAPI +NineDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ); + +HRESULT WINAPI +NineDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ); + +HRESULT WINAPI +NineDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ); + +HRESULT WINAPI +NineDevice9_SetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value ); + +HRESULT WINAPI +NineDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ); + +HRESULT WINAPI +NineDevice9_SetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value ); + +HRESULT WINAPI +NineDevice9_ValidateDevice( struct NineDevice9 *This, + DWORD *pNumPasses ); + +HRESULT WINAPI +NineDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ); + +HRESULT WINAPI +NineDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ); + +HRESULT WINAPI +NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ); + +HRESULT WINAPI +NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ); + +HRESULT WINAPI +NineDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ); + +HRESULT WINAPI +NineDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ); + +HRESULT WINAPI +NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ); + +BOOL WINAPI +NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ); + +float WINAPI +NineDevice9_GetNPatchMode( struct NineDevice9 *This ); + +HRESULT WINAPI +NineDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ); + +HRESULT WINAPI +NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT startIndex, + UINT primCount ); + +HRESULT WINAPI +NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ); + +HRESULT WINAPI +NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex, + UINT NumVertices, + UINT PrimitiveCount, + const void *pIndexData, + D3DFORMAT IndexDataFormat, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ); + +HRESULT WINAPI +NineDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ); + +HRESULT WINAPI +NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ); + +HRESULT WINAPI +NineDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ); + +HRESULT WINAPI +NineDevice9_GetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 **ppDecl ); + +HRESULT WINAPI +NineDevice9_SetFVF( struct NineDevice9 *This, + DWORD FVF ); + +HRESULT WINAPI +NineDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ); + +HRESULT WINAPI +NineDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ); + +HRESULT WINAPI +NineDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ); + +HRESULT WINAPI +NineDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ); + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ); + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ); + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ); + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ); + +HRESULT WINAPI +NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ); + +HRESULT WINAPI +NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ); + +HRESULT WINAPI +NineDevice9_SetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ); + +HRESULT WINAPI +NineDevice9_GetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 **ppStreamData, + UINT *pOffsetInBytes, + UINT *pStride ); + +HRESULT WINAPI +NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT Setting ); + +HRESULT WINAPI +NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ); + +HRESULT WINAPI +NineDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ); + +HRESULT WINAPI +NineDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData /*, + UINT *pBaseVertexIndex */ ); + +HRESULT WINAPI +NineDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ); + +HRESULT WINAPI +NineDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ); + +HRESULT WINAPI +NineDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ); + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ); + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ); + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ); + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ); + +HRESULT WINAPI +NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ); + +HRESULT WINAPI +NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ); + +HRESULT WINAPI +NineDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ); + +HRESULT WINAPI +NineDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ); + +HRESULT WINAPI +NineDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ); + +HRESULT WINAPI +NineDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ); + +#endif /* _NINE_DEVICE9_H_ */ diff --git a/src/gallium/state_trackers/nine/device9ex.c b/src/gallium/state_trackers/nine/device9ex.c new file mode 100644 index 00000000000..00d460bdee4 --- /dev/null +++ b/src/gallium/state_trackers/nine/device9ex.c @@ -0,0 +1,400 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9ex.h" +#include "swapchain9ex.h" + +#include "nine_helpers.h" + +#define DBG_CHANNEL DBG_DEVICE + +static HRESULT +NineDevice9Ex_ctor( struct NineDevice9Ex *This, + struct NineUnknownParams *pParams, + struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + IDirect3D9Ex *pD3D9Ex, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX ) +{ + This->base.ex = TRUE; + This->base.pFullscreenDisplayMode = pFullscreenDisplayMode; + + return NineDevice9_ctor(&This->base, pParams, + pScreen, pCreationParameters, pCaps, + pPresentationParameters, + (IDirect3D9 *)pD3D9Ex, pPresentationGroup, pCTX); +} + +static void +NineDevice9Ex_dtor( struct NineDevice9Ex *This ) +{ + NineDevice9_dtor(&This->base); +} + +HRESULT WINAPI +NineDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This, + UINT width, + UINT height, + float *rows, + float *columns ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_ComposeRects( struct NineDevice9Ex *This, + IDirect3DSurface9 *pSrc, + IDirect3DSurface9 *pDst, + IDirect3DVertexBuffer9 *pSrcRectDescs, + UINT NumRects, + IDirect3DVertexBuffer9 *pDstRectDescs, + D3DCOMPOSERECTSOP Operation, + int Xoffset, + int Yoffset ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + unsigned i; + HRESULT hr; + + for (i = 0; i < This->base.nswapchains; i++) { + hr = NineSwapChain9_Present(This->base.swapchains[i], pSourceRect, pDestRect, + hDestWindowOverride, pDirtyRegion, dwFlags); + if (FAILED(hr)) { return hr; } + } + + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This, + UINT iSwapChain ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This, + IDirect3DResource9 **pResourceArray, + UINT32 NumResources ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ) +{ + DBG("This=%p hDestinationWindow=%p\n", + This, hDestinationWindow); + + /* TODO: handle the other return values */ + return D3D_OK; +} + +HRESULT WINAPI +NineDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ) +{ + HRESULT hr = D3D_OK; + unsigned i; + + DBG("This=%p pPresentationParameters=%p pFullscreenDisplayMode=%p\n", This, pPresentationParameters, pFullscreenDisplayMode); + + for (i = 0; i < This->base.nswapchains; ++i) { + D3DDISPLAYMODEEX *mode = NULL; + D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; + if (pFullscreenDisplayMode) mode = &(pFullscreenDisplayMode[i]); + hr = NineSwapChain9_Resize(This->base.swapchains[i], params, mode); + if (FAILED(hr)) + return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST; + } + + NineDevice9_SetRenderTarget( + (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]); + + + return hr; +} + +HRESULT WINAPI +NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + struct NineSwapChain9Ex *swapchain; + + user_assert(iSwapChain < This->base.nswapchains, D3DERR_INVALIDCALL); + + swapchain = NineSwapChain9Ex(This->base.swapchains[iSwapChain]); + return NineSwapChain9Ex_GetDisplayModeEx(swapchain, pMode, pRotation); +} + +IDirect3DDevice9ExVtbl NineDevice9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineDevice9_TestCooperativeLevel, + (void *)NineDevice9_GetAvailableTextureMem, + (void *)NineDevice9_EvictManagedResources, + (void *)NineDevice9_GetDirect3D, + (void *)NineDevice9_GetDeviceCaps, + (void *)NineDevice9_GetDisplayMode, + (void *)NineDevice9_GetCreationParameters, + (void *)NineDevice9_SetCursorProperties, + (void *)NineDevice9_SetCursorPosition, + (void *)NineDevice9_ShowCursor, + (void *)NineDevice9_CreateAdditionalSwapChain, + (void *)NineDevice9_GetSwapChain, + (void *)NineDevice9_GetNumberOfSwapChains, + (void *)NineDevice9_Reset, + (void *)NineDevice9_Present, + (void *)NineDevice9_GetBackBuffer, + (void *)NineDevice9_GetRasterStatus, + (void *)NineDevice9_SetDialogBoxMode, + (void *)NineDevice9_SetGammaRamp, + (void *)NineDevice9_GetGammaRamp, + (void *)NineDevice9_CreateTexture, + (void *)NineDevice9_CreateVolumeTexture, + (void *)NineDevice9_CreateCubeTexture, + (void *)NineDevice9_CreateVertexBuffer, + (void *)NineDevice9_CreateIndexBuffer, + (void *)NineDevice9_CreateRenderTarget, + (void *)NineDevice9_CreateDepthStencilSurface, + (void *)NineDevice9_UpdateSurface, + (void *)NineDevice9_UpdateTexture, + (void *)NineDevice9_GetRenderTargetData, + (void *)NineDevice9_GetFrontBufferData, + (void *)NineDevice9_StretchRect, + (void *)NineDevice9_ColorFill, + (void *)NineDevice9_CreateOffscreenPlainSurface, + (void *)NineDevice9_SetRenderTarget, + (void *)NineDevice9_GetRenderTarget, + (void *)NineDevice9_SetDepthStencilSurface, + (void *)NineDevice9_GetDepthStencilSurface, + (void *)NineDevice9_BeginScene, + (void *)NineDevice9_EndScene, + (void *)NineDevice9_Clear, + (void *)NineDevice9_SetTransform, + (void *)NineDevice9_GetTransform, + (void *)NineDevice9_MultiplyTransform, + (void *)NineDevice9_SetViewport, + (void *)NineDevice9_GetViewport, + (void *)NineDevice9_SetMaterial, + (void *)NineDevice9_GetMaterial, + (void *)NineDevice9_SetLight, + (void *)NineDevice9_GetLight, + (void *)NineDevice9_LightEnable, + (void *)NineDevice9_GetLightEnable, + (void *)NineDevice9_SetClipPlane, + (void *)NineDevice9_GetClipPlane, + (void *)NineDevice9_SetRenderState, + (void *)NineDevice9_GetRenderState, + (void *)NineDevice9_CreateStateBlock, + (void *)NineDevice9_BeginStateBlock, + (void *)NineDevice9_EndStateBlock, + (void *)NineDevice9_SetClipStatus, + (void *)NineDevice9_GetClipStatus, + (void *)NineDevice9_GetTexture, + (void *)NineDevice9_SetTexture, + (void *)NineDevice9_GetTextureStageState, + (void *)NineDevice9_SetTextureStageState, + (void *)NineDevice9_GetSamplerState, + (void *)NineDevice9_SetSamplerState, + (void *)NineDevice9_ValidateDevice, + (void *)NineDevice9_SetPaletteEntries, + (void *)NineDevice9_GetPaletteEntries, + (void *)NineDevice9_SetCurrentTexturePalette, + (void *)NineDevice9_GetCurrentTexturePalette, + (void *)NineDevice9_SetScissorRect, + (void *)NineDevice9_GetScissorRect, + (void *)NineDevice9_SetSoftwareVertexProcessing, + (void *)NineDevice9_GetSoftwareVertexProcessing, + (void *)NineDevice9_SetNPatchMode, + (void *)NineDevice9_GetNPatchMode, + (void *)NineDevice9_DrawPrimitive, + (void *)NineDevice9_DrawIndexedPrimitive, + (void *)NineDevice9_DrawPrimitiveUP, + (void *)NineDevice9_DrawIndexedPrimitiveUP, + (void *)NineDevice9_ProcessVertices, + (void *)NineDevice9_CreateVertexDeclaration, + (void *)NineDevice9_SetVertexDeclaration, + (void *)NineDevice9_GetVertexDeclaration, + (void *)NineDevice9_SetFVF, + (void *)NineDevice9_GetFVF, + (void *)NineDevice9_CreateVertexShader, + (void *)NineDevice9_SetVertexShader, + (void *)NineDevice9_GetVertexShader, + (void *)NineDevice9_SetVertexShaderConstantF, + (void *)NineDevice9_GetVertexShaderConstantF, + (void *)NineDevice9_SetVertexShaderConstantI, + (void *)NineDevice9_GetVertexShaderConstantI, + (void *)NineDevice9_SetVertexShaderConstantB, + (void *)NineDevice9_GetVertexShaderConstantB, + (void *)NineDevice9_SetStreamSource, + (void *)NineDevice9_GetStreamSource, + (void *)NineDevice9_SetStreamSourceFreq, + (void *)NineDevice9_GetStreamSourceFreq, + (void *)NineDevice9_SetIndices, + (void *)NineDevice9_GetIndices, + (void *)NineDevice9_CreatePixelShader, + (void *)NineDevice9_SetPixelShader, + (void *)NineDevice9_GetPixelShader, + (void *)NineDevice9_SetPixelShaderConstantF, + (void *)NineDevice9_GetPixelShaderConstantF, + (void *)NineDevice9_SetPixelShaderConstantI, + (void *)NineDevice9_GetPixelShaderConstantI, + (void *)NineDevice9_SetPixelShaderConstantB, + (void *)NineDevice9_GetPixelShaderConstantB, + (void *)NineDevice9_DrawRectPatch, + (void *)NineDevice9_DrawTriPatch, + (void *)NineDevice9_DeletePatch, + (void *)NineDevice9_CreateQuery, + (void *)NineDevice9Ex_SetConvolutionMonoKernel, + (void *)NineDevice9Ex_ComposeRects, + (void *)NineDevice9Ex_PresentEx, + (void *)NineDevice9Ex_GetGPUThreadPriority, + (void *)NineDevice9Ex_SetGPUThreadPriority, + (void *)NineDevice9Ex_WaitForVBlank, + (void *)NineDevice9Ex_CheckResourceResidency, + (void *)NineDevice9Ex_SetMaximumFrameLatency, + (void *)NineDevice9Ex_GetMaximumFrameLatency, + (void *)NineDevice9Ex_CheckDeviceState, + (void *)NineDevice9Ex_CreateRenderTargetEx, + (void *)NineDevice9Ex_CreateOffscreenPlainSurfaceEx, + (void *)NineDevice9Ex_CreateDepthStencilSurfaceEx, + (void *)NineDevice9Ex_ResetEx, + (void *)NineDevice9Ex_GetDisplayModeEx +}; + +static const GUID *NineDevice9Ex_IIDs[] = { + &IID_IDirect3DDevice9Ex, + &IID_IDirect3DDevice9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineDevice9Ex_new( struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + IDirect3D9Ex *pD3D9Ex, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX, + struct NineDevice9Ex **ppOut ) +{ + BOOL lock; + lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED); + + NINE_NEW(Device9Ex, ppOut, lock, + pScreen, pCreationParameters, pCaps, pPresentationParameters, + pFullscreenDisplayMode, pD3D9Ex, pPresentationGroup, pCTX); +} + diff --git a/src/gallium/state_trackers/nine/device9ex.h b/src/gallium/state_trackers/nine/device9ex.h new file mode 100644 index 00000000000..a31c720553a --- /dev/null +++ b/src/gallium/state_trackers/nine/device9ex.h @@ -0,0 +1,149 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_DEVICE9EX_H_ +#define _NINE_DEVICE9EX_H_ + +#include "device9.h" + +struct NineDevice9Ex +{ + struct NineDevice9 base; +}; +static INLINE struct NineDevice9Ex * +NineDevice9Ex( void *data ) +{ + return (struct NineDevice9Ex *)data; +} + +HRESULT +NineDevice9Ex_new( struct pipe_screen *pScreen, + D3DDEVICE_CREATION_PARAMETERS *pCreationParameters, + D3DCAPS9 *pCaps, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode, + IDirect3D9Ex *pD3D9Ex, + ID3DPresentGroup *pPresentationGroup, + struct d3dadapter9_context *pCTX, + struct NineDevice9Ex **ppOut ); + +HRESULT WINAPI +NineDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This, + UINT width, + UINT height, + float *rows, + float *columns ); + +HRESULT WINAPI +NineDevice9Ex_ComposeRects( struct NineDevice9Ex *This, + IDirect3DSurface9 *pSrc, + IDirect3DSurface9 *pDst, + IDirect3DVertexBuffer9 *pSrcRectDescs, + UINT NumRects, + IDirect3DVertexBuffer9 *pDstRectDescs, + D3DCOMPOSERECTSOP Operation, + int Xoffset, + int Yoffset ); + +HRESULT WINAPI +NineDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ); + +HRESULT WINAPI +NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ); + +HRESULT WINAPI +NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ); + +HRESULT WINAPI +NineDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This, + UINT iSwapChain ); + +HRESULT WINAPI +NineDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This, + IDirect3DResource9 **pResourceArray, + UINT32 NumResources ); + +HRESULT WINAPI +NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ); + +HRESULT WINAPI +NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ); + +HRESULT WINAPI +NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ); + +HRESULT WINAPI +NineDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ); + +HRESULT WINAPI +NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ); + +HRESULT WINAPI +NineDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ); + +HRESULT WINAPI +NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ); + +HRESULT WINAPI +NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ); + +#endif /* _NINE_DEVICE9EX_H_ */ diff --git a/src/gallium/state_trackers/nine/device9video.c b/src/gallium/state_trackers/nine/device9video.c new file mode 100644 index 00000000000..65cc6a05c68 --- /dev/null +++ b/src/gallium/state_trackers/nine/device9video.c @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9video.h" + +#define DBG_CHANNEL DBG_DEVICEVIDEO + +HRESULT WINAPI +NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineDevice9Video_CreateCryptoSession( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + IDirect3DCryptoSession9 **ppCryptoSession, + HANDLE *pCryptoHandle ) +{ + STUB(D3DERR_INVALIDCALL); +} + +IDirect3DDevice9VideoVtbl NineDevice9Video_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineDevice9Video_GetContentProtectionCaps, + (void *)NineDevice9Video_CreateAuthenticatedChannel, + (void *)NineDevice9Video_CreateCryptoSession +}; diff --git a/src/gallium/state_trackers/nine/device9video.h b/src/gallium/state_trackers/nine/device9video.h new file mode 100644 index 00000000000..ca041e55fbc --- /dev/null +++ b/src/gallium/state_trackers/nine/device9video.h @@ -0,0 +1,57 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_DEVICE9VIDEO_H_ +#define _NINE_DEVICE9VIDEO_H_ + +#include "iunknown.h" + +struct NineDevice9Video +{ + struct NineUnknown base; +}; +static INLINE struct NineDevice9Video * +NineDevice9Video( void *data ) +{ + return (struct NineDevice9Video *)data; +} + +HRESULT WINAPI +NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ); + +HRESULT WINAPI +NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ); + +HRESULT WINAPI +NineDevice9Video_CreateCryptoSession( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + IDirect3DCryptoSession9 **ppCryptoSession, + HANDLE *pCryptoHandle ); + +#endif /* _NINE_DEVICE9VIDEO_H_ */ diff --git a/src/gallium/state_trackers/nine/guid.c b/src/gallium/state_trackers/nine/guid.c new file mode 100644 index 00000000000..5034feb4d71 --- /dev/null +++ b/src/gallium/state_trackers/nine/guid.c @@ -0,0 +1,66 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "guid.h" + +const GUID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; +const GUID IID_ID3D9Adapter = { 0xBF6C7B9A, 0xF0BE, 0x11DF, { 0x81, 0xE3, 0x7F, 0x57, 0xDF, 0xD7, 0x20, 0x85 } }; +const GUID IID_IDirect3D9ExOverlayExtension = { 0x187AEB13, 0xAAF5, 0x4C59, { 0x87, 0x6D, 0xE0, 0x59, 0x08, 0x8C, 0x0D, 0xF8 } }; +const GUID IID_IDirect3DAuthenticatedChannel9 = { 0xFF24BEEE, 0xDA21, 0x4BEB, { 0x98, 0xB5, 0xD2, 0xF8, 0x99, 0xF9, 0x8A, 0xF9 } }; +const GUID IID_IDirect3DBaseTexture9 = { 0x580CA87E, 0x1D3C, 0x4D54, { 0x99, 0x1D, 0xB7, 0xD3, 0xE3, 0xC2, 0x98, 0xCE } }; +const GUID IID_IDirect3DCryptoSession9 = { 0xFA0AB799, 0x7A9C, 0x48CA, { 0x8C, 0x5B, 0x23, 0x7E, 0x71, 0xA5, 0x44, 0x34 } }; +const GUID IID_IDirect3DCubeTexture9 = { 0xFFF32F81, 0xD953, 0x473A, { 0x92, 0x23, 0x93, 0xD6, 0x52, 0xAB, 0xA9, 0x3F } }; +const GUID IID_IDirect3DDevice9 = { 0xD0223B96, 0xBF7A, 0x43FD, { 0x92, 0xBD, 0xA4, 0x3B, 0x0D, 0x82, 0xB9, 0xEB } }; +const GUID IID_IDirect3DDevice9Ex = { 0xB18B10CE, 0x2649, 0x405A, { 0x87, 0x0F, 0x95, 0xF7, 0x77, 0xD4, 0x31, 0x3A } }; +const GUID IID_IDirect3DDevice9Video = { 0x26DC4561, 0xA1EE, 0x4AE7, { 0x96, 0xDA, 0x11, 0x8A, 0x36, 0xC0, 0xEC, 0x95 } }; +const GUID IID_IDirect3DIndexBuffer9 = { 0x7C9DD65E, 0xD3F7, 0x4529, { 0xAC, 0xEE, 0x78, 0x58, 0x30, 0xAC, 0xDE, 0x35 } }; +const GUID IID_IDirect3DPixelShader9 = { 0x6D3BDBDC, 0x5B02, 0x4415, { 0xB8, 0x52, 0xCE, 0x5E, 0x8B, 0xCC, 0xB2, 0x89 } }; +const GUID IID_IDirect3DQuery9 = { 0xD9771460, 0xA695, 0x4F26, { 0xBB, 0xD3, 0x27, 0xB8, 0x40, 0xB5, 0x41, 0xCC } }; +const GUID IID_IDirect3DResource9 = { 0x05EEC05D, 0x8F7D, 0x4362, { 0xB9, 0x99, 0xD1, 0xBA, 0xF3, 0x57, 0xC7, 0x4 } }; +const GUID IID_IDirect3DStateBlock9 = { 0xB07C4FE5, 0x310D, 0x4BA8, { 0xA2, 0x3C, 0x4F, 0x0F, 0x20, 0x6F, 0x21, 0x8B } }; +const GUID IID_IDirect3DSurface9 = { 0x0CFBAF3A, 0x9FF6, 0x429A, { 0x99, 0xB3, 0xA2, 0x79, 0x6A, 0xF8, 0xB8, 0x9B } }; +const GUID IID_IDirect3DSwapChain9 = { 0x794950F2, 0xADFC, 0x458A, { 0x90, 0x5E, 0x10, 0xA1, 0x0B, 0x0B, 0x50, 0x3B } }; +const GUID IID_IDirect3DSwapChain9Ex = { 0x91886CAF, 0x1C3D, 0x4D2E, { 0xA0, 0xAB, 0x3E, 0x4C, 0x7D, 0x8D, 0x33, 0x3 } }; +const GUID IID_IDirect3DTexture9 = { 0x85C31227, 0x3DE5, 0x4F00, { 0x9B, 0x3A, 0xF1, 0x1A, 0xC3, 0x8C, 0x18, 0xB5 } }; +const GUID IID_IDirect3DVertexBuffer9 = { 0xB64BB1B5, 0xFD70, 0x4DF6, { 0xBF, 0x91, 0x19, 0xD0, 0xA1, 0x24, 0x55, 0xE3 } }; +const GUID IID_IDirect3DVertexDeclaration9 = { 0xDD13C59C, 0x36FA, 0x4098, { 0xA8, 0xFB, 0xC7, 0xED, 0x39, 0xDC, 0x85, 0x46 } }; +const GUID IID_IDirect3DVertexShader9 = { 0xEFC5557E, 0x6265, 0x4613, { 0x8A, 0x94, 0x43, 0x85, 0x78, 0x89, 0xEB, 0x36 } }; +const GUID IID_IDirect3DVolume9 = { 0x24F416E6, 0x1F67, 0x4AA7, { 0xB8, 0x8E, 0xD3, 0x3F, 0x6F, 0x31, 0x28, 0xA1 } }; +const GUID IID_IDirect3DVolumeTexture9 = { 0x2518526C, 0xE789, 0x4111, { 0xA7, 0xB9, 0x47, 0xEF, 0x32, 0x8D, 0x13, 0xE6 } }; + +boolean +GUID_equal( const GUID *a, + const GUID *b ) +{ + unsigned i; + + if (!a || !b) + return FALSE; + + if (a->Data1 != b->Data1 || + a->Data2 != b->Data2 || + a->Data3 != b->Data3) { return FALSE; } + for (i = 0; i < 8; i++) { + if (a->Data4[i] != b->Data4[i]) { return FALSE; } + } + return TRUE; +} diff --git a/src/gallium/state_trackers/nine/guid.h b/src/gallium/state_trackers/nine/guid.h new file mode 100644 index 00000000000..1f9ff009ad8 --- /dev/null +++ b/src/gallium/state_trackers/nine/guid.h @@ -0,0 +1,36 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_GUID_H_ +#define _NINE_GUID_H_ + +#include "pipe/p_compiler.h" + +#include "d3d9types.h" + +extern const GUID IID_ID3D9Adapter; + +boolean +GUID_equal( const GUID *a, + const GUID *b ); + +#endif /* _NINE_GUID_H_ */ diff --git a/src/gallium/state_trackers/nine/indexbuffer9.c b/src/gallium/state_trackers/nine/indexbuffer9.c new file mode 100644 index 00000000000..c5606f1c757 --- /dev/null +++ b/src/gallium/state_trackers/nine/indexbuffer9.c @@ -0,0 +1,218 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "indexbuffer9.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "pipe/p_format.h" +#include "util/u_box.h" + +#define DBG_CHANNEL DBG_INDEXBUFFER + +HRESULT +NineIndexBuffer9_ctor( struct NineIndexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DINDEXBUFFER_DESC *pDesc ) +{ + struct pipe_resource *info = &This->base.info; + HRESULT hr; + DBG("This=%p pParams=%p pDesc=%p Usage=%s\n", + This, pParams, pDesc, nine_D3DUSAGE_to_str(pDesc->Usage)); + + This->pipe = pParams->device->pipe; + + info->screen = pParams->device->screen; + info->target = PIPE_BUFFER; + info->format = PIPE_FORMAT_R8_UNORM; + info->width0 = pDesc->Size; + info->flags = 0; + + info->bind = PIPE_BIND_INDEX_BUFFER | PIPE_BIND_TRANSFER_WRITE; + if (!(pDesc->Usage & D3DUSAGE_WRITEONLY)) + info->bind |= PIPE_BIND_TRANSFER_READ; + + info->usage = PIPE_USAGE_DEFAULT; + if (pDesc->Usage & D3DUSAGE_DYNAMIC) + info->usage = PIPE_USAGE_STREAM; + if (pDesc->Pool == D3DPOOL_SYSTEMMEM) + info->usage = PIPE_USAGE_STAGING; + + /* if (This->desc.Usage & D3DUSAGE_DONOTCLIP) { } */ + /* if (This->desc.Usage & D3DUSAGE_NONSECURE) { } */ + /* if (This->desc.Usage & D3DUSAGE_NPATCHES) { } */ + /* if (This->desc.Usage & D3DUSAGE_POINTS) { } */ + /* if (This->desc.Usage & D3DUSAGE_RTPATCHES) { } */ + /* if (This->desc.Usage & D3DUSAGE_SOFTWAREPROCESSING) { } */ + + info->height0 = 1; + info->depth0 = 1; + info->array_size = 1; + info->last_level = 0; + info->nr_samples = 0; + + hr = NineResource9_ctor(&This->base, pParams, TRUE, D3DRTYPE_INDEXBUFFER, + pDesc->Pool); + if (FAILED(hr)) + return hr; + + This->buffer.buffer = This->base.resource; + This->buffer.offset = 0; + This->map_count = 0; + + switch (pDesc->Format) { + case D3DFMT_INDEX16: This->buffer.index_size = 2; break; + case D3DFMT_INDEX32: This->buffer.index_size = 4; break; + default: + user_assert(!"Invalid index format.", D3DERR_INVALIDCALL); + break; + } + This->buffer.user_buffer = NULL; + + pDesc->Type = D3DRTYPE_INDEXBUFFER; + This->desc = *pDesc; + + return D3D_OK; +} + +void +NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This ) +{ + if (This->transfer) { NineIndexBuffer9_Unlock(This); } + + NineResource9_dtor(&This->base); +} + +const struct pipe_index_buffer * +NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This ) +{ + return &This->buffer; +} + +HRESULT WINAPI +NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + struct pipe_box box; + void *data; + UINT count; + const unsigned usage = d3dlock_buffer_to_pipe_transfer_usage(Flags); + + DBG("This=%p OffsetToLock=%u SizeToLock=%u ppbData=%p Flags=%i " + "transfer=%p map_count=%u\n", This, OffsetToLock, + SizeToLock, ppbData, Flags, This->transfer, This->map_count); + + count = ++This->map_count; + + if (SizeToLock == 0) { + SizeToLock = This->desc.Size - OffsetToLock; + user_warn(OffsetToLock != 0); + } + + u_box_1d(OffsetToLock, SizeToLock, &box); + + if (unlikely(count != 1)) { + DBG("Lock has been called on already locked buffer." + "Unmapping before mapping again."); + This->pipe->transfer_unmap(This->pipe, This->transfer); + } + data = This->pipe->transfer_map(This->pipe, This->base.resource, 0, + usage, &box, &This->transfer); + if (!This->transfer) { + DBG("pipe::transfer_map failed\n" + " usage = %u\n" + " box.x = %u\n" + " box.width = %u\n", + usage, box.x, box.width); + } + *ppbData = data; + DBG("Returning memory at %p at address %p\n", *ppbData, ppbData); + + return D3D_OK; +} + +HRESULT WINAPI +NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ) +{ + DBG("This=%p\n", This); + if (!This->map_count) { + DBG("Unmap called without a previous map call.\n"); + return D3D_OK; + } + if (--This->map_count) { + DBG("Ignoring unmap.\n"); + return D3D_OK; + } + This->pipe->transfer_unmap(This->pipe, This->transfer); + This->transfer = NULL; + return D3D_OK; +} + +HRESULT WINAPI +NineIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This, + D3DINDEXBUFFER_DESC *pDesc ) +{ + user_assert(pDesc, E_POINTER); + *pDesc = This->desc; + return D3D_OK; +} + +IDirect3DIndexBuffer9Vtbl NineIndexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineResource9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineIndexBuffer9_Lock, + (void *)NineIndexBuffer9_Unlock, + (void *)NineIndexBuffer9_GetDesc +}; + +static const GUID *NineIndexBuffer9_IIDs[] = { + &IID_IDirect3DIndexBuffer9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineIndexBuffer9_new( struct NineDevice9 *pDevice, + D3DINDEXBUFFER_DESC *pDesc, + struct NineIndexBuffer9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(IndexBuffer9, ppOut, /* args */ pDevice, pDesc); +} diff --git a/src/gallium/state_trackers/nine/indexbuffer9.h b/src/gallium/state_trackers/nine/indexbuffer9.h new file mode 100644 index 00000000000..0982a93fbb1 --- /dev/null +++ b/src/gallium/state_trackers/nine/indexbuffer9.h @@ -0,0 +1,88 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_INDEXBUFFER9_H_ +#define _NINE_INDEXBUFFER9_H_ + +#include "resource9.h" + +#include "pipe/p_state.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_index_buffer; +struct pipe_transfer; +struct NineDevice9; + +struct NineIndexBuffer9 +{ + struct NineResource9 base; + + /* g3d stuff */ + struct pipe_context *pipe; + struct pipe_index_buffer buffer; + struct pipe_transfer *transfer; + UINT map_count; + + D3DINDEXBUFFER_DESC desc; +}; +static INLINE struct NineIndexBuffer9 * +NineIndexBuffer9( void *data ) +{ + return (struct NineIndexBuffer9 *)data; +} + +HRESULT +NineIndexBuffer9_new( struct NineDevice9 *pDevice, + D3DINDEXBUFFER_DESC *pDesc, + struct NineIndexBuffer9 **ppOut ); + +HRESULT +NineIndexBuffer9_ctor( struct NineIndexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DINDEXBUFFER_DESC *pDesc ); + +void +NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This ); + +/*** Nine private ***/ + +const struct pipe_index_buffer * +NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This ); + +/*** Direct3D public ***/ + +HRESULT WINAPI +NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ); + +HRESULT WINAPI +NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ); + +HRESULT WINAPI +NineIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This, + D3DINDEXBUFFER_DESC *pDesc ); + +#endif /* _NINE_INDEXBUFFER9_H_ */ diff --git a/src/gallium/state_trackers/nine/iunknown.c b/src/gallium/state_trackers/nine/iunknown.c new file mode 100644 index 00000000000..aff8041ec64 --- /dev/null +++ b/src/gallium/state_trackers/nine/iunknown.c @@ -0,0 +1,126 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "iunknown.h" +#include "util/u_atomic.h" +#include "nine_helpers.h" + +#define DBG_CHANNEL DBG_UNKNOWN + +HRESULT +NineUnknown_ctor( struct NineUnknown *This, + struct NineUnknownParams *pParams ) +{ + This->refs = pParams->container ? 0 : 1; + This->bind = 0; + This->forward = !This->refs; + This->container = pParams->container; + This->device = pParams->device; + if (This->refs && This->device) + NineUnknown_AddRef(NineUnknown(This->device)); + + This->vtable = pParams->vtable; + This->guids = pParams->guids; + This->dtor = pParams->dtor; + + return D3D_OK; +} + +void +NineUnknown_dtor( struct NineUnknown *This ) +{ + FREE(This); +} + +HRESULT WINAPI +NineUnknown_QueryInterface( struct NineUnknown *This, + REFIID riid, + void **ppvObject ) +{ + unsigned i = 0; + + if (!ppvObject) return E_POINTER; + + do { + if (GUID_equal(This->guids[i], riid)) { + *ppvObject = This; + assert(This->refs); + NineUnknown_AddRef(This); + return S_OK; + } + } while (This->guids[++i]); + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI +NineUnknown_AddRef( struct NineUnknown *This ) +{ + ULONG r; + if (This->forward) + return NineUnknown_AddRef(This->container); + else + r = p_atomic_inc_return(&This->refs); + + if (r == 1) { + if (This->device) + NineUnknown_AddRef(NineUnknown(This->device)); + /* This shouldn't be necessary: + if (This->container) + NineUnknown_Bind(NineUnknown(This->container)); */ + } + return r; +} + +ULONG WINAPI +NineUnknown_Release( struct NineUnknown *This ) +{ + if (This->forward) + return NineUnknown_Release(This->container); + + ULONG r = p_atomic_dec_return(&This->refs); + + if (r == 0) { + if (This->device) { + if (NineUnknown_Release(NineUnknown(This->device)) == 0) + return r; /* everything's gone */ + } + if (This->container) { + /* NineUnknown_Unbind(NineUnknown(This->container)); */ + } else + if (This->bind == 0) { + This->dtor(This); + } + } + return r; +} + +HRESULT WINAPI +NineUnknown_GetDevice( struct NineUnknown *This, + IDirect3DDevice9 **ppDevice ) +{ + user_assert(ppDevice, E_POINTER); + NineUnknown_AddRef(NineUnknown(This->device)); + *ppDevice = (IDirect3DDevice9 *)This->device; + return D3D_OK; +} diff --git a/src/gallium/state_trackers/nine/iunknown.h b/src/gallium/state_trackers/nine/iunknown.h new file mode 100644 index 00000000000..4c83ddd8e4e --- /dev/null +++ b/src/gallium/state_trackers/nine/iunknown.h @@ -0,0 +1,153 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_IUNKNOWN_H_ +#define _NINE_IUNKNOWN_H_ + +#include "pipe/p_compiler.h" + +#include "util/u_memory.h" + +#include "guid.h" +#include "nine_debug.h" +#include "nine_quirk.h" + +#include "d3d9.h" + +struct Nine9; +struct NineDevice9; + +struct NineUnknown +{ + /* pointer to vtable */ + void *vtable; + + int32_t refs; /* external reference count */ + int32_t bind; /* internal bind count */ + boolean forward; /* whether to forward references to the container */ + + struct NineUnknown *container; /* referenced if (refs | bind) */ + struct NineDevice9 *device; /* referenced if (refs) */ + + const GUID **guids; /* for QueryInterface */ + + void (*dtor)(void *data); /* top-level dtor */ +}; +static INLINE struct NineUnknown * +NineUnknown( void *data ) +{ + return (struct NineUnknown *)data; +} + +/* Use this instead of a shitload of arguments: */ +struct NineUnknownParams +{ + void *vtable; + const GUID **guids; + void (*dtor)(void *data); + struct NineUnknown *container; + struct NineDevice9 *device; +}; + +HRESULT +NineUnknown_ctor( struct NineUnknown *This, + struct NineUnknownParams *pParams ); + +void +NineUnknown_dtor( struct NineUnknown *This ); + +/*** Direct3D public methods ***/ + +HRESULT WINAPI +NineUnknown_QueryInterface( struct NineUnknown *This, + REFIID riid, + void **ppvObject ); + +ULONG WINAPI +NineUnknown_AddRef( struct NineUnknown *This ); + +ULONG WINAPI +NineUnknown_Release( struct NineUnknown *This ); + +HRESULT WINAPI +NineUnknown_GetDevice( struct NineUnknown *This, + IDirect3DDevice9 **ppDevice ); + +/*** Nine private methods ***/ + +static INLINE void +NineUnknown_Destroy( struct NineUnknown *This ) +{ + assert(!(This->refs | This->bind)); + This->dtor(This); +} + +static INLINE UINT +NineUnknown_Bind( struct NineUnknown *This ) +{ + UINT b = ++This->bind; + assert(b); + if (b == 1 && This->container) { + if (This->container != NineUnknown(This->device)) + NineUnknown_Bind(This->container); + } + return b; +} + +static INLINE UINT +NineUnknown_Unbind( struct NineUnknown *This ) +{ + UINT b = --This->bind; + if (!b) { + if (This->container) { + if (This->container != NineUnknown(This->device)) + NineUnknown_Unbind(This->container); + } else + if (This->refs == 0) { + This->dtor(This); + } + } + return b; +} + +static INLINE void +NineUnknown_ConvertRefToBind( struct NineUnknown *This ) +{ + NineUnknown_Bind(This); + NineUnknown_Release(This); +} + +/* Detach from container. */ +static INLINE void +NineUnknown_Detach( struct NineUnknown *This ) +{ + assert(This->container && !This->forward); + if (This->refs) + NineUnknown_Unbind(This->container); + if (This->bind) + NineUnknown_Unbind(This->container); + This->container = NULL; + if (!(This->refs | This->bind)) + This->dtor(This); +} + +#endif /* _NINE_IUNKNOWN_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_debug.c b/src/gallium/state_trackers/nine/nine_debug.c new file mode 100644 index 00000000000..4779192ecc3 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_debug.c @@ -0,0 +1,104 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_debug.h" + +#include <ctype.h> + +static const struct debug_named_value nine_debug_flags[] = { + { "unknown", DBG_UNKNOWN, "IUnknown implementation." }, + { "adapter", DBG_ADAPTER, "ID3D9Adapter implementation." }, + { "overlay", DBG_OVERLAYEXTENSION, "IDirect3D9ExOverlayExtension implementation." }, + { "auth", DBG_AUTHENTICATEDCHANNEL, "IDirect3DAuthenticatedChannel9 implementation." }, + { "basetex", DBG_BASETEXTURE, "IDirect3DBaseTexture9 implementation." }, + { "crypto", DBG_CRYPTOSESSION, "IDirect3DCryptoSession9 implementation." }, + { "cubetex", DBG_CUBETEXTURE, "IDirect3DCubeTexture9 implementation." }, + { "device", DBG_DEVICE, "IDirect3DDevice9(Ex) implementation." }, + { "video", DBG_DEVICEVIDEO, "IDirect3DDeviceVideo9 implementation." }, + { "ibuf", DBG_INDEXBUFFER, "IDirect3DIndexBuffer9 implementation." }, + { "ps", DBG_PIXELSHADER, "IDirect3DPixelShader9 implementation." }, + { "query", DBG_QUERY, "IDirect3DQuery9 implementation." }, + { "res", DBG_RESOURCE, "IDirect3DResource9 implementation." }, + { "state", DBG_STATEBLOCK, "IDirect3DStateBlock9 implementation." }, + { "surf", DBG_SURFACE, "IDirect3DSurface9 implementation." }, + { "swap", DBG_SWAPCHAIN, "IDirect3DSwapChain9(Ex) implementation." }, + { "tex", DBG_TEXTURE, "IDirect3DTexture9 implementation." }, + { "vbuf", DBG_VERTEXBUFFER, "IDirect3DVertexBuffer9 implementation." }, + { "vdecl", DBG_VERTEXDECLARATION, "IDirect3DVertexDeclaration9 implementation." }, + { "vs", DBG_VERTEXSHADER, "IDirect3DVertexShader9 implementation." }, + { "3dsurf", DBG_VOLUME, "IDirect3DVolume9 implementation." }, + { "3dtex", DBG_VOLUMETEXTURE, "IDirect3DVolumeTexture9 implementation." }, + { "shader", DBG_SHADER, "Shader token stream translator." }, + { "ff", DBG_FF, "Fixed function emulation." }, + { "user", DBG_USER, "User errors, both fixable and unfixable." }, + { "error", DBG_ERROR, "Driver errors, always visible." }, + { "warn", DBG_WARN, "Driver warnings, always visible in debug builds." }, + DEBUG_NAMED_VALUE_END +}; + +void +_nine_debug_printf( unsigned long flag, + const char *func, + const char *fmt, + ... ) +{ + static boolean first = TRUE; + static unsigned long dbg_flags = DBG_ERROR | DBG_WARN; + + if (first) { + first = FALSE; + dbg_flags |= debug_get_flags_option("NINE_DEBUG", nine_debug_flags, 0); + } + if (dbg_flags & flag) { + const char *f = func ? strrchr(func, '_') : NULL; + va_list ap; + + /* inside a class this will print nine:classinlowercase:func: while + * outside a class (rarely used) it will just print nine:func: + * the reason for lower case is simply to match the filenames, as it + * will also strip off the "Nine" */ + if (f && strncmp(func, "Nine", 4) == 0) { + char klass[96]; /* no class name is this long */ + char *ptr = klass; + for (func += 4; func != f; ++func) { *ptr++ = tolower(*func); } + *ptr = '\0'; + + debug_printf("nine:%s:%s: ", klass, ++f); + } else if (func) { + debug_printf("nine:%s: ", func); + } + + va_start(ap, fmt); + debug_vprintf(fmt, ap); + va_end(ap); + } +} + +void +_nine_stub( const char *file, + const char *func, + unsigned line ) +{ + const char *r = strrchr(file, '/'); + if (r == NULL) { r = strrchr(file, '\\'); } + debug_printf("nine:%s:%d: %s STUB!\n", r ? ++r : file, line, func); +} diff --git a/src/gallium/state_trackers/nine/nine_debug.h b/src/gallium/state_trackers/nine/nine_debug.h new file mode 100644 index 00000000000..4c017eaac7e --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_debug.h @@ -0,0 +1,135 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_DEBUG_H_ +#define _NINE_DEBUG_H_ + +#include "util/u_debug.h" + +void +_nine_debug_printf( unsigned long flag, + const char *func, + const char *fmt, + ... ) _util_printf_format(3,4); + +#define ERR(fmt, ...) _nine_debug_printf(DBG_ERROR, __FUNCTION__, fmt, ## __VA_ARGS__) + +#ifdef DEBUG +#define WARN(fmt, ...) _nine_debug_printf(DBG_WARN, __FUNCTION__, fmt, ## __VA_ARGS__) +#define WARN_ONCE(fmt, ...) \ + do { \ + static boolean once = TRUE; \ + if (once) { \ + once = FALSE; \ + _nine_debug_printf(DBG_WARN, __FUNCTION__, fmt, ## __VA_ARGS__); \ + } \ + } while(0) +#else +#define WARN(fmt, ...) +#define WARN_ONCE(fmt, ...) +#endif + +#ifdef DEBUG +#define DBG_FLAG(flag, fmt, ...) \ + _nine_debug_printf(flag, __FUNCTION__, fmt, ## __VA_ARGS__) +#else +#define DBG_FLAG(flag, fmt, ...) +#endif +#define DBG(fmt, ...) DBG_FLAG(DBG_CHANNEL, fmt, ## __VA_ARGS__) + +#define DBG_UNKNOWN (1<< 0) +#define DBG_ADAPTER (1<< 1) +#define DBG_OVERLAYEXTENSION (1<< 2) +#define DBG_AUTHENTICATEDCHANNEL (1<< 3) +#define DBG_BASETEXTURE (1<< 4) +#define DBG_CRYPTOSESSION (1<< 5) +#define DBG_CUBETEXTURE (1<< 6) +#define DBG_DEVICE (1<< 7) +#define DBG_DEVICEVIDEO (1<< 8) +#define DBG_INDEXBUFFER (1<< 9) +#define DBG_PIXELSHADER (1<<10) +#define DBG_QUERY (1<<11) +#define DBG_RESOURCE (1<<12) +#define DBG_STATEBLOCK (1<<13) +#define DBG_SURFACE (1<<14) +#define DBG_SWAPCHAIN (1<<15) +#define DBG_TEXTURE (1<<16) +#define DBG_VERTEXBUFFER (1<<17) +#define DBG_VERTEXDECLARATION (1<<18) +#define DBG_VERTEXSHADER (1<<19) +#define DBG_VOLUME (1<<20) +#define DBG_VOLUMETEXTURE (1<<21) +#define DBG_SHADER (1<<22) +#define DBG_FF (1<<23) +#define DBG_USER (1<<24) +#define DBG_ERROR (1<<25) +#define DBG_WARN (1<<26) + +void +_nine_stub( const char *file, + const char *func, + unsigned line ); + +#ifdef DEBUG +#define STUB(ret) \ + do { \ + _nine_stub(__FILE__, __FUNCTION__, __LINE__); \ + return ret; \ + } while (0) +#else +#define STUB(ret) do { return ret; } while (0) +#endif + +/* the expression for this macro is equivalent of that to assert, however this + * macro is designed to be used in conditionals ala + * if (user_error(required condition)) { assertion failed } + * It also prints debug message if the assertion fails. */ +#ifdef DEBUG +#define user_error(x) \ + (!(x) ? (DBG_FLAG(DBG_USER, "User assertion failed: `%s'\n", #x), TRUE) \ + : FALSE) +#else +#define user_error(x) (!(x) ? TRUE : FALSE) +#endif + +#ifdef DEBUG +#define user_warn(x) \ + if ((x)) { DBG_FLAG(DBG_USER, "User warning: `%s'\n", #x); } +#else +#define user_warn(x) +#endif + +/* nonfatal assert */ +#define user_assert(x, r) \ + do { \ + if (user_error(x)) { \ + return r; \ + } \ + } while (0) + +#define ret_err(x, r) \ + do { \ + ERR(x); \ + return r; \ + } while(0) + +#endif /* _NINE_DEBUG_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_defines.h b/src/gallium/state_trackers/nine/nine_defines.h new file mode 100644 index 00000000000..aa3b257de09 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_defines.h @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_DEFINES_H_ +#define _NINE_DEFINES_H_ + +#include "pipe/p_defines.h" + + +#define NINE_RESOURCE_FLAG_LOCKABLE (PIPE_RESOURCE_FLAG_ST_PRIV << 1) +#define NINE_RESOURCE_FLAG_DUMMY (PIPE_RESOURCE_FLAG_ST_PRIV << 2) + +/* vertexdeclaration9.c */ +unsigned nine_d3d9_to_nine_declusage(unsigned usage, unsigned index); + +#define NINE_DECLUSAGE_POSITION(i) ( 0 + (i)) +#define NINE_DECLUSAGE_BLENDWEIGHT(i) ( 5 + (i)) +#define NINE_DECLUSAGE_BLENDINDICES(i) ( 9 + (i)) +#define NINE_DECLUSAGE_NORMAL(i) (13 + (i)) +#define NINE_DECLUSAGE_PSIZE 15 +#define NINE_DECLUSAGE_TEXCOORD(i) (16 + (i)) +#define NINE_DECLUSAGE_TANGENT(i) (32 + (i)) +#define NINE_DECLUSAGE_BINORMAL(i) (34 + (i)) +#define NINE_DECLUSAGE_TESSFACTOR 36 +#define NINE_DECLUSAGE_POSITIONT 37 +#define NINE_DECLUSAGE_COLOR(i) (38 + (i)) +#define NINE_DECLUSAGE_DEPTH 43 +#define NINE_DECLUSAGE_FOG 44 +#define NINE_DECLUSAGE_SAMPLE 45 +#define NINE_DECLUSAGE_NONE 46 +#define NINE_DECLUSAGE_LAST NINE_DECLUSAGE_NONE +#define NINE_DECLUSAGE_COUNT (NINE_DECLUSAGE_LAST + 1) + +#define NINED3DCLEAR_DEPTHSTENCIL (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL) + +#endif /* _NINE_DEFINES_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_dump.c b/src/gallium/state_trackers/nine/nine_dump.c new file mode 100644 index 00000000000..1ca550586e4 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_dump.c @@ -0,0 +1,813 @@ + +#include "nine_debug.h" +#include "nine_pipe.h" + +#include <stdio.h> +#include "util/u_memory.h" +#include "util/u_math.h" + +#include "nine_dump.h" + +#ifdef DEBUG + +static char __thread tls[128]; + +const char *nine_D3DDEVTYPE_to_str(D3DDEVTYPE type) +{ + switch (type) { + case D3DDEVTYPE_HAL: return "HAL"; + case D3DDEVTYPE_NULLREF: return "NULLREF"; + case D3DDEVTYPE_REF: return "REF"; + case D3DDEVTYPE_SW: return "SW"; + default: + return "(D3DDEVTYPE_?)"; + } +} + +const char *nine_D3DPOOL_to_str(D3DPOOL pool) +{ + switch (pool) { + case D3DPOOL_DEFAULT: return "DEFAULT"; + case D3DPOOL_MANAGED: return "MANAGED"; + case D3DPOOL_SYSTEMMEM: return "SYSTEMMEM"; + case D3DPOOL_SCRATCH: return "SCRATCH"; + default: + return "(D3DPOOL_?)"; + } +} + +const char *nine_D3DSAMP_to_str(DWORD samp) +{ + switch (samp) { + case D3DSAMP_ADDRESSU: return "ADDRESSU"; + case D3DSAMP_ADDRESSV: return "ADDRESSV"; + case D3DSAMP_ADDRESSW: return "ADDRESSW"; + case D3DSAMP_BORDERCOLOR: return "BORDERCOLOR"; + case D3DSAMP_MAGFILTER: return "MAGFILTER"; + case D3DSAMP_MINFILTER: return "MINFILTER"; + case D3DSAMP_MIPFILTER: return "MIPFILTER"; + case D3DSAMP_MIPMAPLODBIAS: return "MIPMAPLODBIAS"; + case D3DSAMP_MAXMIPLEVEL: return "MAXMIPLEVEL"; + case D3DSAMP_MAXANISOTROPY: return "MAXANISOTROPY"; + case D3DSAMP_SRGBTEXTURE: return "SRGBTEXTURE"; + case D3DSAMP_ELEMENTINDEX: return "ELEMENTINDEX"; + case D3DSAMP_DMAPOFFSET: return "DMAPOFFSET"; + default: + return "(D3DSAMP_?)"; + } +} + +#define C2S(n,s) \ + do { \ + if (usage & D3DUSAGE_##n) p += snprintf(&tls[p], sizeof(tls) - p, s); \ + } while(0) +const char *nine_D3DUSAGE_to_str(DWORD usage) +{ + int p = 0; + tls[0] = 0; + C2S(AUTOGENMIPMAP, "MIPGEN"); + C2S(WRITEONLY, "WO"); + C2S(DYNAMIC, "DYNAMIC"); + C2S(DEPTHSTENCIL, "DS"); + C2S(RENDERTARGET, "RT"); + C2S(SOFTWAREPROCESSING, "SW"); + C2S(DONOTCLIP, "NOCLIP"); + C2S(POINTS, "POINTS"); + C2S(DMAP, "DMAP"); + C2S(NPATCHES, "NPATCHES"); + C2S(RTPATCHES, "RTPATCHES"); + C2S(TEXTAPI, "TEXTAPI"); + C2S(NONSECURE, "NONSECURE"); + C2S(RESTRICTED_CONTENT, "RESTRICTED_CONTENT"); + C2S(RESTRICT_SHARED_RESOURCE, "RESTRICT_SHARED_RESOURCE"); + C2S(RESTRICT_SHARED_RESOURCE_DRIVER, "RESTRICT_SHARED_RESOURCE_DRIVER"); + return tls; +} +#undef C2S + +#define C2S(n) \ + do { \ + if (flags & D3DPRESENTFLAG_##n) \ + p += snprintf(&tls[p], sizeof(tls) - p, #n); \ + } while(0) +const char *nine_D3DPRESENTFLAG_to_str(DWORD flags) +{ + int p = 0; + tls[0] = 0; + C2S(DEVICECLIP); + C2S(DISCARD_DEPTHSTENCIL); + C2S(LOCKABLE_BACKBUFFER); + C2S(NOAUTOROTATE); + C2S(UNPRUNEDMODE); + C2S(VIDEO); + C2S(OVERLAY_LIMITEDRGB); + C2S(OVERLAY_YCbCr_BT709); + C2S(OVERLAY_YCbCr_xvYCC); + C2S(RESTRICTED_CONTENT); + C2S(RESTRICT_SHARED_RESOURCE_DRIVER); + return tls; +} +#undef C2S + +#define C2S(n) \ + do { \ + if (lock & D3DLOCK_##n) p += snprintf(&tls[p], sizeof(tls) - p, #n"|"); \ + } while(0) +const char *nine_D3DLOCK_to_str(DWORD lock) +{ + int p = 0; + tls[0] = 0; + C2S(DISCARD); + C2S(DONOTWAIT); + C2S(NO_DIRTY_UPDATE); + C2S(NOOVERWRITE); + C2S(NOSYSLOCK); + C2S(READONLY); + return tls; +} +#undef C2S + +const char *nine_D3DRTYPE_to_str(D3DRESOURCETYPE type) +{ + switch (type) { + case D3DRTYPE_SURFACE: return "SURFACE"; + case D3DRTYPE_VOLUME: return "VOLUME"; + case D3DRTYPE_TEXTURE: return "TEXTURE"; + case D3DRTYPE_VOLUMETEXTURE: return "VOLUMETEXTURE"; + case D3DRTYPE_CUBETEXTURE: return "CUBETEXTURE"; + case D3DRTYPE_VERTEXBUFFER: return "VERTEXBUFFER"; + case D3DRTYPE_INDEXBUFFER: return "INDEXBUFFER"; + default: + return "(D3DRTYPE_?)"; + } +} + +const char *nine_D3DQUERYTYPE_to_str(D3DQUERYTYPE type) +{ + switch (type) { + case D3DQUERYTYPE_VCACHE: return "VCACHE"; + case D3DQUERYTYPE_RESOURCEMANAGER: return "RESOURCEMANAGER"; + case D3DQUERYTYPE_VERTEXSTATS: return "VERTEXSTATS"; + case D3DQUERYTYPE_EVENT: return "EVENT"; + case D3DQUERYTYPE_OCCLUSION: return "OCCLUSION"; + case D3DQUERYTYPE_TIMESTAMP: return "TIMESTAMP"; + case D3DQUERYTYPE_TIMESTAMPDISJOINT: return "TIMESTAMPDISJOINT"; + case D3DQUERYTYPE_TIMESTAMPFREQ: return "TIMESTAMPFREQ"; + case D3DQUERYTYPE_PIPELINETIMINGS: return "PIPELINETIMINGS"; + case D3DQUERYTYPE_INTERFACETIMINGS: return "INTERFACETIMINGS"; + case D3DQUERYTYPE_VERTEXTIMINGS: return "VERTEXTIMINGS"; + case D3DQUERYTYPE_PIXELTIMINGS: return "PIXELTIMINGS"; + case D3DQUERYTYPE_BANDWIDTHTIMINGS: return "BANDWIDTHTIMINGS"; + case D3DQUERYTYPE_CACHEUTILIZATION: return "CACHEUTILIZATION"; + default: + return "(D3DQUERYTYPE_?)"; + } +} + +const char *nine_D3DTSS_to_str(D3DTEXTURESTAGESTATETYPE type) +{ + switch (type) { + case D3DTSS_COLOROP: return "COLOROP"; + case D3DTSS_ALPHAOP: return "ALPHAOP"; + case D3DTSS_COLORARG0: return "COLORARG0"; + case D3DTSS_COLORARG1: return "COLORARG1"; + case D3DTSS_COLORARG2: return "COLORARG2"; + case D3DTSS_ALPHAARG0: return "ALPHAARG0"; + case D3DTSS_ALPHAARG1: return "ALPHAARG1"; + case D3DTSS_ALPHAARG2: return "ALPHAARG2"; + case D3DTSS_RESULTARG: return "RESULTARG"; + case D3DTSS_BUMPENVMAT00: return "BUMPENVMAT00"; + case D3DTSS_BUMPENVMAT01: return "BUMPENVMAT01"; + case D3DTSS_BUMPENVMAT10: return "BUMPENVMAT10"; + case D3DTSS_BUMPENVMAT11: return "BUMPENVMAT11"; + case D3DTSS_BUMPENVLSCALE: return "BUMPENVLSCALE"; + case D3DTSS_BUMPENVLOFFSET: return "BUMPENVLOFFSET"; + case D3DTSS_TEXCOORDINDEX: return "TEXCOORDINDEX"; + case D3DTSS_TEXTURETRANSFORMFLAGS: return "TEXTURETRANSFORMFLAGS"; + case D3DTSS_CONSTANT: return "CONSTANT"; + default: + return "(D3DTSS_?)"; + } +} + +#define D3DTOP_TO_STR_CASE(n) case D3DTOP_##n: return #n +const char *nine_D3DTOP_to_str(D3DTEXTUREOP top) +{ + switch (top) { + D3DTOP_TO_STR_CASE(DISABLE); + D3DTOP_TO_STR_CASE(SELECTARG1); + D3DTOP_TO_STR_CASE(SELECTARG2); + D3DTOP_TO_STR_CASE(MODULATE); + D3DTOP_TO_STR_CASE(MODULATE2X); + D3DTOP_TO_STR_CASE(MODULATE4X); + D3DTOP_TO_STR_CASE(ADD); + D3DTOP_TO_STR_CASE(ADDSIGNED); + D3DTOP_TO_STR_CASE(ADDSIGNED2X); + D3DTOP_TO_STR_CASE(SUBTRACT); + D3DTOP_TO_STR_CASE(ADDSMOOTH); + D3DTOP_TO_STR_CASE(BLENDDIFFUSEALPHA); + D3DTOP_TO_STR_CASE(BLENDTEXTUREALPHA); + D3DTOP_TO_STR_CASE(BLENDFACTORALPHA); + D3DTOP_TO_STR_CASE(BLENDTEXTUREALPHAPM); + D3DTOP_TO_STR_CASE(BLENDCURRENTALPHA); + D3DTOP_TO_STR_CASE(PREMODULATE); + D3DTOP_TO_STR_CASE(MODULATEALPHA_ADDCOLOR); + D3DTOP_TO_STR_CASE(MODULATECOLOR_ADDALPHA); + D3DTOP_TO_STR_CASE(MODULATEINVALPHA_ADDCOLOR); + D3DTOP_TO_STR_CASE(MODULATEINVCOLOR_ADDALPHA); + D3DTOP_TO_STR_CASE(BUMPENVMAP); + D3DTOP_TO_STR_CASE(BUMPENVMAPLUMINANCE); + D3DTOP_TO_STR_CASE(DOTPRODUCT3); + D3DTOP_TO_STR_CASE(MULTIPLYADD); + D3DTOP_TO_STR_CASE(LERP); + default: + return "(D3DTOP_?)"; + } +} + +static const char * +nine_D3DLIGHTTYPE_to_str(D3DLIGHTTYPE type) +{ + switch (type) { + case D3DLIGHT_POINT: return "POINT"; + case D3DLIGHT_SPOT: return "SPOT"; + case D3DLIGHT_DIRECTIONAL: return "DIRECTIONAL"; + default: + return "(D3DLIGHT_?)"; + } +} + +static const char * +nine_D3DTA_to_str(DWORD value) +{ + switch (value & D3DTA_SELECTMASK) { + case D3DTA_DIFFUSE: return "DIFFUSE"; + case D3DTA_CURRENT: return "CURRENT"; + case D3DTA_TEXTURE: return "TEXTURE"; + case D3DTA_TFACTOR: return "TFACTOR"; + case D3DTA_SPECULAR: return "SPECULAR"; + case D3DTA_TEMP: return "TEMP"; + case D3DTA_CONSTANT: return "CONSTANT"; + default: + return "(D3DTA_?)"; + } +} + +static const char * +nine_D3DTSS_TCI_to_str(DWORD value) +{ + switch (value & 0xf0000) { + case D3DTSS_TCI_PASSTHRU: return "PASSTHRU"; + case D3DTSS_TCI_CAMERASPACENORMAL: return "CAMERASPACENORMAL"; + case D3DTSS_TCI_CAMERASPACEPOSITION: return "CAMERASPACEPOSITION"; + case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + return "CAMERASPACEREFLECTIONVECTOR"; + case D3DTSS_TCI_SPHEREMAP: return "SPHEREMAP"; + default: + return "(D3DTSS_TCI_?)"; + } +} + +static const char * +nine_D3DTTFF_to_str(DWORD value) +{ + switch (value) { + case D3DTTFF_DISABLE: return "DISABLE"; + case D3DTTFF_COUNT1: return "COUNT1"; + case D3DTTFF_COUNT2: return "COUNT2"; + case D3DTTFF_COUNT3: return "COUNT3"; + case D3DTTFF_COUNT4: return "COUNT4"; + case D3DTTFF_PROJECTED: return "PROJECTED"; + default: + return "(D3DTTFF_?)"; + } +} + +void +nine_dump_D3DLIGHT9(unsigned ch, const D3DLIGHT9 *lit) +{ + DBG_FLAG(ch, "D3DLIGHT9(%p):\n" + "Type: %s\n" + "Diffuse: (%f %f %f %f)\n" + "Specular: (%f %f %f %f)\n" + "Ambient: (%f %f %f %f)\n" + "Position: (%f %f %f)\n" + "Direction: (%f %f %f)\n" + "Range: %f\n" + "Falloff: %f\n" + "Attenuation: %f + %f * d + %f * d^2\n" + "Theta: %f deg\n" + "Phi: %f deg\n", lit, + nine_D3DLIGHTTYPE_to_str(lit->Type), + lit->Diffuse.r,lit->Diffuse.r,lit->Diffuse.g,lit->Diffuse.a, + lit->Specular.r,lit->Specular.r,lit->Specular.g,lit->Specular.a, + lit->Ambient.r,lit->Ambient.r,lit->Ambient.g,lit->Ambient.a, + lit->Position.x,lit->Position.y,lit->Position.z, + lit->Direction.x,lit->Direction.y,lit->Direction.z, + lit->Range,lit->Falloff, + lit->Attenuation0,lit->Attenuation1,lit->Attenuation2, + lit->Theta * 360.0f / M_PI,lit->Phi * 360.0f / M_PI); +} + +void +nine_dump_D3DMATERIAL9(unsigned ch, const D3DMATERIAL9 *mat) +{ + DBG_FLAG(ch, "D3DMATERIAL9(%p):\n" + "Diffuse: (%f %f %f %f)\n" + "Specular: (%f %f %f %f)\n" + "Ambient: (%f %f %f %f)\n" + "Emissive: (%f %f %f %f)\n" + "Power: %f\n", mat, + mat->Diffuse.r,mat->Diffuse.r,mat->Diffuse.g,mat->Diffuse.a, + mat->Specular.r,mat->Specular.r,mat->Specular.g,mat->Specular.a, + mat->Ambient.r,mat->Ambient.r,mat->Ambient.g,mat->Ambient.a, + mat->Emissive.r,mat->Emissive.r,mat->Emissive.g,mat->Emissive.a, + mat->Power); +} + +void +nine_dump_D3DTSS_value(unsigned ch, D3DTEXTURESTAGESTATETYPE type, DWORD value) +{ + float rgba[4]; + + switch (type) { + case D3DTSS_COLOROP: + case D3DTSS_ALPHAOP: + DBG_FLAG(ch, "D3DTSS_%s = %s\n", + nine_D3DTSS_to_str(type), nine_D3DTOP_to_str(value)); + break; + case D3DTSS_COLORARG0: + case D3DTSS_COLORARG1: + case D3DTSS_COLORARG2: + case D3DTSS_ALPHAARG0: + case D3DTSS_ALPHAARG1: + case D3DTSS_ALPHAARG2: + case D3DTSS_RESULTARG: + DBG_FLAG(ch, "D3DTSS_%s = %s%s%s\n", + nine_D3DTSS_to_str(type), + (value & D3DTA_COMPLEMENT) ? "COMPLEMENT " : "", + (value & D3DTA_ALPHAREPLICATE) ? "ALPHAREPLICATE " : "", + nine_D3DTA_to_str(value)); + break; + case D3DTSS_BUMPENVMAT00: + case D3DTSS_BUMPENVMAT01: + case D3DTSS_BUMPENVMAT10: + case D3DTSS_BUMPENVMAT11: + case D3DTSS_BUMPENVLSCALE: + case D3DTSS_BUMPENVLOFFSET: + DBG_FLAG(ch, "D3DTSS_%s = %f\n", + nine_D3DTSS_to_str(type), asfloat(value)); + break; + case D3DTSS_TEXCOORDINDEX: + DBG_FLAG(ch, "D3DTSS_TEXCOORDINDEX = %s %u\n", + nine_D3DTSS_TCI_to_str(value), + value & 0xffff); + break; + case D3DTSS_TEXTURETRANSFORMFLAGS: + DBG_FLAG(ch, "D3DTSS_TEXTURETRANSFORMFLAGS = %s\n", + nine_D3DTTFF_to_str(value)); + break; + case D3DTSS_CONSTANT: + d3dcolor_to_rgba(rgba, value); + DBG_FLAG(ch, "D3DTSS_CONSTANT = %f %f %f %F\n", + rgba[0],rgba[1],rgba[2],rgba[3]); + break; + default: + DBG_FLAG(ch, "D3DTSS_? = 0x%08x\n", value); + break; + } +} + +void +nine_dump_D3DADAPTER_IDENTIFIER9(unsigned ch, const D3DADAPTER_IDENTIFIER9 *id) +{ + DBG_FLAG(ch, "D3DADAPTER_IDENTIFIER9(%p):\n" + "Driver: %s\n" + "Description: %s\n" + "DeviceName: %s\n" + "DriverVersion: %08x.%08x\n" + "VendorId: %x\n" + "DeviceId: %x\n" + "SubSysId: %x\n" + "Revision: %u\n" + "GUID: %08x.%04x.%04x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n" + "WHQLLevel: %u\n", id, id->Driver, id->Description, + id->DeviceName, + id->DriverVersionLowPart, id->DriverVersionHighPart, + id->VendorId, id->DeviceId, id->SubSysId, + id->Revision, + id->DeviceIdentifier.Data1, + id->DeviceIdentifier.Data2, + id->DeviceIdentifier.Data3, + id->DeviceIdentifier.Data4[0], + id->DeviceIdentifier.Data4[1], + id->DeviceIdentifier.Data4[2], + id->DeviceIdentifier.Data4[3], + id->DeviceIdentifier.Data4[4], + id->DeviceIdentifier.Data4[5], + id->DeviceIdentifier.Data4[6], + id->DeviceIdentifier.Data4[7], + id->WHQLLevel); +} + +#define C2S(args...) p += snprintf(&s[p],c-p,args) + +#define CAP_CASE(m,p,n) \ + do { \ + if (caps->m & p##_##n) \ + C2S(" "#n); \ + else \ + C2S(" ("#n")"); \ + } while(0) + +void +nine_dump_D3DCAPS9(unsigned ch, const D3DCAPS9 *caps) +{ + const int c = 1 << 17; + int p = 0; + char *s = (char *)MALLOC(c); + + if (!s) { + DBG_FLAG(ch, "D3DCAPS9(%p): (out of memory)\n", caps); + return; + } + + C2S("DeviceType: %s\n", nine_D3DDEVTYPE_to_str(caps->DeviceType)); + + C2S("AdapterOrdinal: %u\nCaps:", caps->AdapterOrdinal); + if (caps->Caps & 0x20000) + C2S(" READ_SCANLINE"); + if (caps->Caps & ~0x20000) + C2S(" %x", caps->Caps & ~0x20000); + + C2S("\nCaps2:"); + CAP_CASE(Caps2, D3DCAPS2, CANAUTOGENMIPMAP); + CAP_CASE(Caps2, D3DCAPS2, CANCALIBRATEGAMMA); + CAP_CASE(Caps2, D3DCAPS2, CANSHARERESOURCE); + CAP_CASE(Caps2, D3DCAPS2, CANMANAGERESOURCE); + CAP_CASE(Caps2, D3DCAPS2, DYNAMICTEXTURES); + CAP_CASE(Caps2, D3DCAPS2, FULLSCREENGAMMA); + + C2S("\nCaps3:"); + CAP_CASE(Caps3, D3DCAPS3, ALPHA_FULLSCREEN_FLIP_OR_DISCARD); + CAP_CASE(Caps3, D3DCAPS3, COPY_TO_VIDMEM); + CAP_CASE(Caps3, D3DCAPS3, COPY_TO_SYSTEMMEM); + CAP_CASE(Caps3, D3DCAPS3, DXVAHD); + CAP_CASE(Caps3, D3DCAPS3, LINEAR_TO_SRGB_PRESENTATION); + + C2S("\nPresentationIntervals:"); + CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, ONE); + CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, TWO); + CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, THREE); + CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, FOUR); + CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, IMMEDIATE); + + C2S("\nCursorCaps:"); + CAP_CASE(CursorCaps, D3DCURSORCAPS, COLOR); + CAP_CASE(CursorCaps, D3DCURSORCAPS, LOWRES); + + C2S("\nDevCaps:"); + CAP_CASE(DevCaps, D3DDEVCAPS, CANBLTSYSTONONLOCAL); + CAP_CASE(DevCaps, D3DDEVCAPS, CANRENDERAFTERFLIP); + CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMITIVES2); + CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMITIVES2EX); + CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMTLVERTEX); + CAP_CASE(DevCaps, D3DDEVCAPS, EXECUTESYSTEMMEMORY); + CAP_CASE(DevCaps, D3DDEVCAPS, EXECUTEVIDEOMEMORY); + CAP_CASE(DevCaps, D3DDEVCAPS, HWRASTERIZATION); + CAP_CASE(DevCaps, D3DDEVCAPS, HWTRANSFORMANDLIGHT); + CAP_CASE(DevCaps, D3DDEVCAPS, NPATCHES); + CAP_CASE(DevCaps, D3DDEVCAPS, PUREDEVICE); + CAP_CASE(DevCaps, D3DDEVCAPS, QUINTICRTPATCHES); + CAP_CASE(DevCaps, D3DDEVCAPS, RTPATCHES); + CAP_CASE(DevCaps, D3DDEVCAPS, RTPATCHHANDLEZERO); + CAP_CASE(DevCaps, D3DDEVCAPS, SEPARATETEXTUREMEMORIES); + CAP_CASE(DevCaps, D3DDEVCAPS, TEXTURENONLOCALVIDMEM); + CAP_CASE(DevCaps, D3DDEVCAPS, TEXTURESYSTEMMEMORY); + CAP_CASE(DevCaps, D3DDEVCAPS, TEXTUREVIDEOMEMORY); + CAP_CASE(DevCaps, D3DDEVCAPS, TLVERTEXSYSTEMMEMORY); + CAP_CASE(DevCaps, D3DDEVCAPS, TLVERTEXVIDEOMEMORY); + + C2S("\nPrimitiveMiscCaps:"); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MASKZ); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLNONE); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLCW); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLCCW); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, COLORWRITEENABLE); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CLIPPLANESCALEDPOINTS); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CLIPTLVERTS); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, TSSARGTEMP); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, BLENDOP); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, NULLREFERENCE); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, INDEPENDENTWRITEMASKS); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, PERSTAGECONSTANT); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, POSTBLENDSRGBCONVERT); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, FOGANDSPECULARALPHA); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, SEPARATEALPHABLEND); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MRTINDEPENDENTBITDEPTHS); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MRTPOSTPIXELSHADERBLENDING); + CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, FOGVERTEXCLAMPED); + + C2S("\nRasterCaps:"); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, ANISOTROPY); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, COLORPERSPECTIVE); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, DITHER); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, DEPTHBIAS); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGRANGE); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGTABLE); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGVERTEX); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, MIPMAPLODBIAS); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, MULTISAMPLE_TOGGLE); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, SCISSORTEST); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, SLOPESCALEDEPTHBIAS); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, WBUFFER); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, WFOG); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZBUFFERLESSHSR); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZFOG); + CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZTEST); + + C2S("\nZCmpCaps:"); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, ALWAYS); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, EQUAL); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, GREATER); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, GREATEREQUAL); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, LESS); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, LESSEQUAL); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, NEVER); + CAP_CASE(ZCmpCaps, D3DPCMPCAPS, NOTEQUAL); + + C2S("\nSrcBlendCaps"); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BLENDFACTOR); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BOTHINVSRCALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BOTHSRCALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, DESTALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, DESTCOLOR); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVDESTALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVDESTCOLOR); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR2); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, ONE); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCALPHA); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCALPHASAT); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCCOLOR); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCCOLOR2); + CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, ZERO); + + C2S("\nDestBlendCaps"); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BLENDFACTOR); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BOTHINVSRCALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BOTHSRCALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, DESTALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, DESTCOLOR); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVDESTALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVDESTCOLOR); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR2); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, ONE); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCALPHA); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCALPHASAT); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCCOLOR); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCCOLOR2); + CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, ZERO); + + C2S("\nAlphaCmpCaps:"); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, ALWAYS); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, EQUAL); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, GREATER); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, GREATEREQUAL); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, LESS); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, LESSEQUAL); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, NEVER); + CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, NOTEQUAL); + + C2S("\nShadeCaps:"); + CAP_CASE(ShadeCaps, D3DPSHADECAPS, ALPHAGOURAUDBLEND); + CAP_CASE(ShadeCaps, D3DPSHADECAPS, COLORGOURAUDRGB); + CAP_CASE(ShadeCaps, D3DPSHADECAPS, FOGGOURAUD); + CAP_CASE(ShadeCaps, D3DPSHADECAPS, SPECULARGOURAUDRGB); + + C2S("\nTextureCaps:"); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, ALPHA); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, ALPHAPALETTE); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, CUBEMAP); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, CUBEMAP_POW2); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPCUBEMAP); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPMAP); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPVOLUMEMAP); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, NONPOW2CONDITIONAL); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, NOPROJECTEDBUMPENV); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, PERSPECTIVE); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, POW2); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, PROJECTED); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, SQUAREONLY); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, TEXREPEATNOTSCALEDBYSIZE); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, VOLUMEMAP); + CAP_CASE(TextureCaps, D3DPTEXTURECAPS, VOLUMEMAP_POW2); + + C2S("\nTextureFilterCaps:"); + /* CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */ + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT); + CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR); + + C2S("\nCubeTextureFilterCaps:"); + /* CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */ + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT); + CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR); + + C2S("\nVolumeTextureFilterCaps:"); + /* CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */ + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT); + CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR); + + C2S("\nTextureAddressCaps:"); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, BORDER); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, CLAMP); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, INDEPENDENTUV); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, MIRROR); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, MIRRORONCE); + CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, WRAP); + + C2S("\nVolumeTextureAddressCaps:"); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, BORDER); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, CLAMP); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, INDEPENDENTUV); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, MIRROR); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, MIRRORONCE); + CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, WRAP); + + C2S("\nLineCaps:"); + CAP_CASE(LineCaps, D3DLINECAPS, ALPHACMP); + CAP_CASE(LineCaps, D3DLINECAPS, ANTIALIAS); + CAP_CASE(LineCaps, D3DLINECAPS, BLEND); + CAP_CASE(LineCaps, D3DLINECAPS, FOG); + CAP_CASE(LineCaps, D3DLINECAPS, TEXTURE); + CAP_CASE(LineCaps, D3DLINECAPS, ZTEST); + + C2S("\nMaxTextureWidth: %u", caps->MaxTextureWidth); + C2S("\nMaxTextureHeight: %u", caps->MaxTextureHeight); + C2S("\nMaxVolumeExtent: %u", caps->MaxVolumeExtent); + C2S("\nMaxTextureRepeat: %u", caps->MaxTextureRepeat); + C2S("\nMaxTextureAspectRatio: %u", caps->MaxTextureAspectRatio); + C2S("\nMaxAnisotropy: %u", caps->MaxAnisotropy); + C2S("\nMaxVertexW: %f", caps->MaxVertexW); + + C2S("\nGuardBandLef,Top,Right,Bottom: %f %f %f %f", + caps->GuardBandLeft, caps->GuardBandTop, + caps->GuardBandRight, caps->GuardBandBottom); + + C2S("\nExtentsAdjust: %f", caps->ExtentsAdjust); + + C2S("\nStencilCaps:"); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, KEEP); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, ZERO); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, REPLACE); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, INCRSAT); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, DECRSAT); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, INVERT); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, INCR); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, DECR); + CAP_CASE(StencilCaps, D3DSTENCILCAPS, TWOSIDED); + + C2S("\nFVFCaps:"); + CAP_CASE(FVFCaps, D3DFVFCAPS, DONOTSTRIPELEMENTS); + CAP_CASE(FVFCaps, D3DFVFCAPS, PSIZE); + CAP_CASE(FVFCaps, D3DFVFCAPS, TEXCOORDCOUNTMASK); + + C2S("\nTextureOpCaps:"); + CAP_CASE(TextureOpCaps, D3DTEXOPCAPS, ADD); + CAP_CASE(TextureOpCaps, D3DTEXOPCAPS, ADDSIGNED); + C2S(" ..."); + + C2S("\nMaxTextureBlendStages: %u", caps->MaxTextureBlendStages); + C2S("\nMaxSimultaneousTextures: %u", caps->MaxTextureBlendStages); + + C2S("\nVertexProcessingCaps:"); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, DIRECTIONALLIGHTS); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, LOCALVIEWER); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, MATERIALSOURCE7); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, NO_TEXGEN_NONLOCALVIEWER); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, POSITIONALLIGHTS); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TEXGEN); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TEXGEN_SPHEREMAP); + CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TWEENING); + + C2S("\nMaxActiveLights: %u", caps->MaxActiveLights); + C2S("\nMaxUserClipPlanes: %u", caps->MaxUserClipPlanes); + C2S("\nMaxVertexBlendMatrices: %u", caps->MaxVertexBlendMatrices); + C2S("\nMaxVertexBlendMatrixIndex: %u", caps->MaxVertexBlendMatrixIndex); + C2S("\nMaxPointSize: %f", caps->MaxPointSize); + C2S("\nMaxPrimitiveCount: 0x%x", caps->MaxPrimitiveCount); + C2S("\nMaxVertexIndex: 0x%x", caps->MaxVertexIndex); + C2S("\nMaxStreams: %u", caps->MaxStreams); + C2S("\nMaxStreamStride: 0x%x", caps->MaxStreamStride); + + C2S("\nVertexShaderVersion: %08x", caps->VertexShaderVersion); + C2S("\nMaxVertexShaderConst: %u", caps->MaxVertexShaderConst); + C2S("\nPixelShaderVersion: %08x", caps->PixelShaderVersion); + C2S("\nPixelShader1xMaxValue: %f", caps->PixelShader1xMaxValue); + + DBG_FLAG(ch, "D3DCAPS9(%p) part 1:\n%s\n", caps, s); + p = 0; + + C2S("DevCaps2:"); + CAP_CASE(DevCaps2, D3DDEVCAPS2, ADAPTIVETESSRTPATCH); + CAP_CASE(DevCaps2, D3DDEVCAPS2, ADAPTIVETESSNPATCH); + CAP_CASE(DevCaps2, D3DDEVCAPS2, CAN_STRETCHRECT_FROM_TEXTURES); + CAP_CASE(DevCaps2, D3DDEVCAPS2, DMAPNPATCH); + CAP_CASE(DevCaps2, D3DDEVCAPS2, PRESAMPLEDDMAPNPATCH); + CAP_CASE(DevCaps2, D3DDEVCAPS2, STREAMOFFSET); + CAP_CASE(DevCaps2, D3DDEVCAPS2, VERTEXELEMENTSCANSHARESTREAMOFFSET); + + C2S("\nMasterAdapterOrdinal: %u", caps->MasterAdapterOrdinal); + C2S("\nAdapterOrdinalInGroup: %u", caps->AdapterOrdinalInGroup); + C2S("\nNumberOfAdaptersInGroup: %u", caps->NumberOfAdaptersInGroup); + + C2S("\nDeclTypes:"); + CAP_CASE(DeclTypes, D3DDTCAPS, UBYTE4); + CAP_CASE(DeclTypes, D3DDTCAPS, UBYTE4N); + CAP_CASE(DeclTypes, D3DDTCAPS, SHORT2N); + CAP_CASE(DeclTypes, D3DDTCAPS, SHORT4N); + CAP_CASE(DeclTypes, D3DDTCAPS, USHORT2N); + CAP_CASE(DeclTypes, D3DDTCAPS, USHORT4N); + CAP_CASE(DeclTypes, D3DDTCAPS, UDEC3); + CAP_CASE(DeclTypes, D3DDTCAPS, DEC3N); + CAP_CASE(DeclTypes, D3DDTCAPS, FLOAT16_2); + CAP_CASE(DeclTypes, D3DDTCAPS, FLOAT16_4); + + C2S("\nNumSimultaneousRTs: %u", caps->NumSimultaneousRTs); + + C2S("\nStretchRectFilterCaps:"); + CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MINFPOINT); + CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MINFLINEAR); + CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MAGFPOINT); + CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR); + + C2S("\nVS20Caps.Caps: Predication=%s", caps->VS20Caps.Caps ? "yes" : "no"); + C2S("\nVS20Caps.DynamicFlowControlDepth: %u", caps->VS20Caps.DynamicFlowControlDepth); + C2S("\nVS20Caps.NumTemps: %u", caps->VS20Caps.NumTemps); + C2S("\nVS20Caps.StaticFlowControlDepth: %u", caps->VS20Caps.StaticFlowControlDepth); + + C2S("\nPS20Caps.Caps: Predication=%s", caps->VS20Caps.Caps ? "yes" : "no"); + C2S("\nPS20Caps.DynamicFlowControlDepth: %u", caps->PS20Caps.DynamicFlowControlDepth); + C2S("\nPS20Caps.NumTemps: %u", caps->PS20Caps.NumTemps); + C2S("\nPS20Caps.StaticFlowControlDepth: %u", caps->PS20Caps.StaticFlowControlDepth); + C2S("\nPS20Caps.NumInstructionSlots: %u", caps->PS20Caps.NumInstructionSlots); + + C2S("\nVertexTextureFilterCaps"); + /* CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */ + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT); + CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR); + + C2S("\nMaxVShaderInstructionsExecuted: %u", caps->MaxVShaderInstructionsExecuted); + C2S("\nMaxPShaderInstructionsExecuted: %u", caps->MaxPShaderInstructionsExecuted); + C2S("\nMaxVertexShader30InstructionSlots: %u >= 512", caps->MaxVertexShader30InstructionSlots); + C2S("\nMaxPixelShader30InstructionSlots: %u >= 512", caps->MaxPixelShader30InstructionSlots); + + DBG_FLAG(ch, "D3DCAPS9(%p) part 2:\n%s\n", caps, s); + + FREE(s); +} + +#endif /* DEBUG */ diff --git a/src/gallium/state_trackers/nine/nine_dump.h b/src/gallium/state_trackers/nine/nine_dump.h new file mode 100644 index 00000000000..d0d4a9eb3aa --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_dump.h @@ -0,0 +1,52 @@ + +#ifndef _NINE_DUMP_H_ +#define _NINE_DUMP_H_ + +#include "d3d9types.h" +#include "d3d9caps.h" + +const char *nine_D3DDEVTYPE_to_str(D3DDEVTYPE); +const char *nine_D3DQUERYTYPE_to_str(D3DQUERYTYPE); +const char *nine_D3DTSS_to_str(D3DTEXTURESTAGESTATETYPE); +const char *nine_D3DTOP_to_str(D3DTEXTUREOP); +const char *nine_D3DPOOL_to_str(D3DPOOL); +const char *nine_D3DRTYPE_to_str(D3DRESOURCETYPE); +const char *nine_D3DUSAGE_to_str(DWORD); +const char *nine_D3DPRESENTFLAG_to_str(DWORD); +const char *nine_D3DLOCK_to_str(DWORD); +const char *nine_D3DSAMP_to_str(DWORD); + +#ifdef DEBUG + +void +nine_dump_D3DADAPTER_IDENTIFIER9(unsigned, const D3DADAPTER_IDENTIFIER9 *); +void +nine_dump_D3DCAPS9(unsigned, const D3DCAPS9 *); +void +nine_dump_D3DLIGHT9(unsigned, const D3DLIGHT9 *); +void +nine_dump_D3DMATERIAL9(unsigned, const D3DMATERIAL9 *); +void +nine_dump_D3DTSS_value(unsigned, D3DTEXTURESTAGESTATETYPE, DWORD); + +#else /* !DEBUG */ + +static INLINE void +nine_dump_D3DADAPTER_IDENTIFIER9(unsigned ch, const D3DADAPTER_IDENTIFIER9 *id) +{ } +static INLINE void +nine_dump_D3DCAPS9(unsigned ch, const D3DCAPS9 *caps) +{ } +static INLINE void +nine_dump_D3DLIGHT9(unsigned ch, const D3DLIGHT9 *light) +{ } +static INLINE void +nine_dump_D3DMATERIAL9(unsigned ch, const D3DMATERIAL9 *mat) +{ } +static INLINE void +nine_dump_D3DTSS_value(unsigned ch, D3DTEXTURESTAGESTATETYPE tss, DWORD value) +{ } + +#endif /* DEBUG */ + +#endif /* _NINE_DUMP_H_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_ff.c b/src/gallium/state_trackers/nine/nine_ff.c new file mode 100644 index 00000000000..d6cb5b2c0ec --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_ff.c @@ -0,0 +1,2257 @@ + +/* FF is big and ugly so feel free to write lines as long as you like. + * Aieeeeeeeee ! + * + * Let me make that clearer: + * Aieeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ! !! !!! + */ + +#include "device9.h" +#include "basetexture9.h" +#include "vertexdeclaration9.h" +#include "vertexshader9.h" +#include "pixelshader9.h" +#include "nine_ff.h" +#include "nine_defines.h" +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "pipe/p_context.h" +#include "tgsi/tgsi_ureg.h" +#include "tgsi/tgsi_dump.h" +#include "util/u_box.h" +#include "util/u_hash_table.h" + +#define NINE_TGSI_LAZY_DEVS 1 + +#define DBG_CHANNEL DBG_FF + +#define NINE_FF_NUM_VS_CONST 256 +#define NINE_FF_NUM_PS_CONST 24 + +#define NINED3DTSS_TCI_DISABLE 0 +#define NINED3DTSS_TCI_PASSTHRU 1 +#define NINED3DTSS_TCI_CAMERASPACENORMAL 2 +#define NINED3DTSS_TCI_CAMERASPACEPOSITION 3 +#define NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 4 +#define NINED3DTSS_TCI_SPHEREMAP 5 + +struct fvec4 +{ + float x, y, z, w; +}; + +struct nine_ff_vs_key +{ + union { + struct { + uint32_t position_t : 1; + uint32_t lighting : 1; + uint32_t darkness : 1; /* lighting enabled but no active lights */ + uint32_t localviewer : 1; + uint32_t vertexpointsize : 1; + uint32_t pointscale : 1; + uint32_t vertexblend : 3; + uint32_t vertexblend_indexed : 1; + uint32_t vertextween : 1; + uint32_t mtl_diffuse : 2; /* 0 = material, 1 = color1, 2 = color2 */ + uint32_t mtl_ambient : 2; + uint32_t mtl_specular : 2; + uint32_t mtl_emissive : 2; + uint32_t fog_mode : 2; + uint32_t fog_range : 1; + uint32_t color0in_one : 1; + uint32_t color1in_one : 1; + uint32_t pad1 : 8; + uint32_t tc_gen : 24; /* 8 * 3 bits */ + uint32_t pad2 : 8; + uint32_t tc_idx : 24; + uint32_t pad3 : 8; + uint32_t tc_dim : 24; /* 8 * 3 bits */ + uint32_t pad4 : 8; + }; + uint64_t value64[2]; /* don't forget to resize VertexShader9.ff_key */ + uint32_t value32[4]; + }; +}; + +/* Texture stage state: + * + * COLOROP D3DTOP 5 bit + * ALPHAOP D3DTOP 5 bit + * COLORARG0 D3DTA 3 bit + * COLORARG1 D3DTA 3 bit + * COLORARG2 D3DTA 3 bit + * ALPHAARG0 D3DTA 3 bit + * ALPHAARG1 D3DTA 3 bit + * ALPHAARG2 D3DTA 3 bit + * RESULTARG D3DTA 1 bit (CURRENT:0 or TEMP:1) + * TEXCOORDINDEX 0 - 7 3 bit + * =========================== + * 32 bit per stage + */ +struct nine_ff_ps_key +{ + union { + struct { + struct { + uint32_t colorop : 5; + uint32_t alphaop : 5; + uint32_t colorarg0 : 3; + uint32_t colorarg1 : 3; + uint32_t colorarg2 : 3; + uint32_t alphaarg0 : 3; + uint32_t alphaarg1 : 3; + uint32_t alphaarg2 : 3; + uint32_t resultarg : 1; /* CURRENT:0 or TEMP:1 */ + uint32_t textarget : 2; /* 1D/2D/3D/CUBE */ + uint32_t projected : 1; + /* that's 32 bit exactly */ + } ts[8]; + uint32_t fog : 1; /* for vFog with programmable VS */ + uint32_t fog_mode : 2; + uint32_t specular : 1; /* 9 32-bit words with this */ + uint8_t colorarg_b4[3]; + uint8_t colorarg_b5[3]; + uint8_t alphaarg_b4[3]; /* 11 32-bit words plus a byte */ + }; + uint64_t value64[6]; /* don't forget to resize PixelShader9.ff_key */ + uint32_t value32[12]; + }; +}; + +static unsigned nine_ff_vs_key_hash(void *key) +{ + struct nine_ff_vs_key *vs = key; + unsigned i; + uint32_t hash = vs->value32[0]; + for (i = 1; i < Elements(vs->value32); ++i) + hash ^= vs->value32[i]; + return hash; +} +static int nine_ff_vs_key_comp(void *key1, void *key2) +{ + struct nine_ff_vs_key *a = (struct nine_ff_vs_key *)key1; + struct nine_ff_vs_key *b = (struct nine_ff_vs_key *)key2; + + return memcmp(a->value64, b->value64, sizeof(a->value64)); +} +static unsigned nine_ff_ps_key_hash(void *key) +{ + struct nine_ff_ps_key *ps = key; + unsigned i; + uint32_t hash = ps->value32[0]; + for (i = 1; i < Elements(ps->value32); ++i) + hash ^= ps->value32[i]; + return hash; +} +static int nine_ff_ps_key_comp(void *key1, void *key2) +{ + struct nine_ff_ps_key *a = (struct nine_ff_ps_key *)key1; + struct nine_ff_ps_key *b = (struct nine_ff_ps_key *)key2; + + return memcmp(a->value64, b->value64, sizeof(a->value64)); +} +static unsigned nine_ff_fvf_key_hash(void *key) +{ + return *(DWORD *)key; +} +static int nine_ff_fvf_key_comp(void *key1, void *key2) +{ + return *(DWORD *)key1 != *(DWORD *)key2; +} + +static void nine_ff_prune_vs(struct NineDevice9 *); +static void nine_ff_prune_ps(struct NineDevice9 *); + +static void nine_ureg_tgsi_dump(struct ureg_program *ureg, boolean override) +{ + if (debug_get_bool_option("NINE_FF_DUMP", FALSE) || override) { + unsigned count; + const struct tgsi_token *toks = ureg_get_tokens(ureg, &count); + tgsi_dump(toks, 0); + ureg_free_tokens(toks); + } +} + +#define _X(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_X) +#define _Y(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_Y) +#define _Z(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_Z) +#define _W(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_W) + +#define _XXXX(r) ureg_scalar(r, TGSI_SWIZZLE_X) +#define _YYYY(r) ureg_scalar(r, TGSI_SWIZZLE_Y) +#define _ZZZZ(r) ureg_scalar(r, TGSI_SWIZZLE_Z) +#define _WWWW(r) ureg_scalar(r, TGSI_SWIZZLE_W) + +#define _XYZW(r) (r) + +/* AL should contain base address of lights table. */ +#define LIGHT_CONST(i) \ + ureg_src_indirect(ureg_src_register(TGSI_FILE_CONSTANT, (i)), _X(AL)) + +#define MATERIAL_CONST(i) \ + ureg_src_register(TGSI_FILE_CONSTANT, 19 + (i)) + +#define MISC_CONST(i) \ + ureg_src_register(TGSI_FILE_CONSTANT, (i)) + +#define _CONST(n) ureg_DECL_constant(ureg, n) + +/* VS FF constants layout: + * + * CONST[ 0.. 3] D3DTS_WORLD * D3DTS_VIEW * D3DTS_PROJECTION + * CONST[ 4.. 7] D3DTS_WORLD * D3DTS_VIEW + * CONST[ 8..11] D3DTS_VIEW * D3DTS_PROJECTION + * CONST[12..15] D3DTS_VIEW + * CONST[16..18] Normal matrix + * + * CONST[19] MATERIAL.Emissive + Material.Ambient * RS.Ambient + * CONST[20] MATERIAL.Diffuse + * CONST[21] MATERIAL.Ambient + * CONST[22] MATERIAL.Specular + * CONST[23].x___ MATERIAL.Power + * CONST[24] MATERIAL.Emissive + * CONST[25] RS.Ambient + * + * CONST[26].x___ RS.PointSizeMin + * CONST[26]._y__ RS.PointSizeMax + * CONST[26].__z_ RS.PointSize + * CONST[26].___w RS.PointScaleA + * CONST[27].x___ RS.PointScaleB + * CONST[27]._y__ RS.PointScaleC + * + * CONST[28].x___ RS.FogEnd + * CONST[28]._y__ 1.0f / (RS.FogEnd - RS.FogStart) + * CONST[28].__z_ RS.FogDensity + * CONST[29] RS.FogColor + + * CONST[30].x___ TWEENFACTOR + * + * CONST[32].x___ LIGHT[0].Type + * CONST[32]._yzw LIGHT[0].Attenuation0,1,2 + * CONST[33] LIGHT[0].Diffuse + * CONST[34] LIGHT[0].Specular + * CONST[35] LIGHT[0].Ambient + * CONST[36].xyz_ LIGHT[0].Position + * CONST[36].___w LIGHT[0].Range + * CONST[37].xyz_ LIGHT[0].Direction + * CONST[37].___w LIGHT[0].Falloff + * CONST[38].x___ cos(LIGHT[0].Theta / 2) + * CONST[38]._y__ cos(LIGHT[0].Phi / 2) + * CONST[38].__z_ 1.0f / (cos(LIGHT[0].Theta / 2) - cos(Light[0].Phi / 2)) + * CONST[39].xyz_ LIGHT[0].HalfVector (for directional lights) + * CONST[39].___w 1 if this is the last active light, 0 if not + * CONST[40] LIGHT[1] + * CONST[48] LIGHT[2] + * CONST[56] LIGHT[3] + * CONST[64] LIGHT[4] + * CONST[72] LIGHT[5] + * CONST[80] LIGHT[6] + * CONST[88] LIGHT[7] + * NOTE: no lighting code is generated if there are no active lights + * + * CONST[100].x___ Viewport 2/width + * CONST[100]._y__ Viewport 2/height + * CONST[100].__z_ Viewport 1/(zmax - zmin) + * CONST[101].x___ Viewport x0 + * CONST[101]._y__ Viewport y0 + * CONST[101].__z_ Viewport z0 + * + * CONST[128..131] D3DTS_TEXTURE0 + * CONST[132..135] D3DTS_TEXTURE1 + * CONST[136..139] D3DTS_TEXTURE2 + * CONST[140..143] D3DTS_TEXTURE3 + * CONST[144..147] D3DTS_TEXTURE4 + * CONST[148..151] D3DTS_TEXTURE5 + * CONST[152..155] D3DTS_TEXTURE6 + * CONST[156..159] D3DTS_TEXTURE7 + * + * CONST[224] D3DTS_WORLDMATRIX[0] + * CONST[228] D3DTS_WORLDMATRIX[1] + * ... + * CONST[252] D3DTS_WORLDMATRIX[7] + */ +struct vs_build_ctx +{ + struct ureg_program *ureg; + const struct nine_ff_vs_key *key; + + unsigned input[PIPE_MAX_ATTRIBS]; + unsigned num_inputs; + + struct ureg_src aVtx; + struct ureg_src aNrm; + struct ureg_src aCol[2]; + struct ureg_src aTex[8]; + struct ureg_src aPsz; + struct ureg_src aInd; + struct ureg_src aWgt; + + struct ureg_src aVtx1; /* tweening */ + struct ureg_src aNrm1; + + struct ureg_src mtlA; + struct ureg_src mtlD; + struct ureg_src mtlS; + struct ureg_src mtlE; +}; + +static INLINE unsigned +get_texcoord_sn(struct pipe_screen *screen) +{ + if (screen->get_param(screen, PIPE_CAP_TGSI_TEXCOORD)) + return TGSI_SEMANTIC_TEXCOORD; + return TGSI_SEMANTIC_GENERIC; +} + +static INLINE struct ureg_src +build_vs_add_input(struct vs_build_ctx *vs, unsigned ndecl) +{ + const unsigned i = vs->num_inputs++; + assert(i < PIPE_MAX_ATTRIBS); + vs->input[i] = ndecl; + return ureg_DECL_vs_input(vs->ureg, i); +} + +/* NOTE: dst may alias src */ +static INLINE void +ureg_normalize3(struct ureg_program *ureg, + struct ureg_dst dst, struct ureg_src src, + struct ureg_dst tmp) +{ +#ifdef NINE_TGSI_LAZY_DEVS + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + + ureg_DP3(ureg, tmp_x, src, src); + ureg_RSQ(ureg, tmp_x, _X(tmp)); + ureg_MUL(ureg, dst, src, _X(tmp)); +#else + ureg_NRM(ureg, dst, src); +#endif +} + +static void * +nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) +{ + const struct nine_ff_vs_key *key = vs->key; + struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + struct ureg_dst oPos, oCol[2], oTex[8], oPsz, oFog; + struct ureg_dst rCol[2]; /* oCol if no fog, TEMP otherwise */ + struct ureg_dst rVtx, rNrm; + struct ureg_dst r[8]; + struct ureg_dst AR; + struct ureg_dst tmp, tmp_x, tmp_z; + unsigned i, c; + unsigned label[32], l = 0; + unsigned num_r = 8; + boolean need_rNrm = key->lighting || key->pointscale; + boolean need_rVtx = key->lighting || key->fog_mode; + const unsigned texcoord_sn = get_texcoord_sn(device->screen); + + vs->ureg = ureg; + + /* Check which inputs we should transform. */ + for (i = 0; i < 8 * 3; i += 3) { + switch ((key->tc_gen >> i) & 0x3) { + case NINED3DTSS_TCI_CAMERASPACENORMAL: + need_rNrm = TRUE; + break; + case NINED3DTSS_TCI_CAMERASPACEPOSITION: + need_rVtx = TRUE; + break; + case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + need_rVtx = need_rNrm = TRUE; + break; + default: + break; + } + } + + /* Declare and record used inputs (needed for linkage with vertex format): + * (texture coordinates handled later) + */ + vs->aVtx = build_vs_add_input(vs, + key->position_t ? NINE_DECLUSAGE_POSITIONT : NINE_DECLUSAGE_POSITION(0)); + + if (need_rNrm) + vs->aNrm = build_vs_add_input(vs, NINE_DECLUSAGE_NORMAL(0)); + + vs->aCol[0] = ureg_imm1f(ureg, 1.0f); + vs->aCol[1] = ureg_imm1f(ureg, 1.0f); + + if (key->lighting || key->darkness) { + const unsigned mask = key->mtl_diffuse | key->mtl_specular | + key->mtl_ambient | key->mtl_emissive; + if ((mask & 0x1) && !key->color0in_one) + vs->aCol[0] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(0)); + if ((mask & 0x2) && !key->color1in_one) + vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(1)); + + vs->mtlD = MATERIAL_CONST(1); + vs->mtlA = MATERIAL_CONST(2); + vs->mtlS = MATERIAL_CONST(3); + vs->mtlE = MATERIAL_CONST(5); + if (key->mtl_diffuse == 1) vs->mtlD = vs->aCol[0]; else + if (key->mtl_diffuse == 2) vs->mtlD = vs->aCol[1]; + if (key->mtl_ambient == 1) vs->mtlA = vs->aCol[0]; else + if (key->mtl_ambient == 2) vs->mtlA = vs->aCol[1]; + if (key->mtl_specular == 1) vs->mtlS = vs->aCol[0]; else + if (key->mtl_specular == 2) vs->mtlS = vs->aCol[1]; + if (key->mtl_emissive == 1) vs->mtlE = vs->aCol[0]; else + if (key->mtl_emissive == 2) vs->mtlE = vs->aCol[1]; + } else { + if (!key->color0in_one) vs->aCol[0] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(0)); + if (!key->color1in_one) vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(1)); + } + + if (key->vertexpointsize) + vs->aPsz = build_vs_add_input(vs, NINE_DECLUSAGE_PSIZE); + + if (key->vertexblend_indexed) + vs->aInd = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDINDICES(0)); + if (key->vertexblend) + vs->aWgt = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDWEIGHT(0)); + if (key->vertextween) { + vs->aVtx1 = build_vs_add_input(vs, NINE_DECLUSAGE_POSITION(1)); + vs->aNrm1 = build_vs_add_input(vs, NINE_DECLUSAGE_NORMAL(1)); + } + + /* Declare outputs: + */ + oPos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); /* HPOS */ + oCol[0] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0)); + oCol[1] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 1)); + + if (key->vertexpointsize || key->pointscale) { + oPsz = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_PSIZE, 0, TGSI_WRITEMASK_X); + oPsz = ureg_writemask(oPsz, TGSI_WRITEMASK_X); + } + if (key->fog_mode) { + /* We apply fog to the vertex colors, oFog is for programmable shaders only ? + */ + oFog = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_FOG, 0, TGSI_WRITEMASK_X); + oFog = ureg_writemask(oFog, TGSI_WRITEMASK_X); + } + + /* Declare TEMPs: + */ + for (i = 0; i < num_r; ++i) + r[i] = ureg_DECL_local_temporary(ureg); + tmp = r[0]; + tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z); + if (key->lighting || key->vertexblend) + AR = ureg_DECL_address(ureg); + + if (key->fog_mode) { + rCol[0] = r[2]; + rCol[1] = r[3]; + } else { + rCol[0] = oCol[0]; + rCol[1] = oCol[1]; + } + + rVtx = ureg_writemask(r[1], TGSI_WRITEMASK_XYZ); + rNrm = ureg_writemask(r[2], TGSI_WRITEMASK_XYZ); + + /* === Vertex transformation / vertex blending: + */ + if (key->vertextween) { + assert(!key->vertexblend); + ureg_LRP(ureg, r[2], _XXXX(_CONST(30)), vs->aVtx, vs->aVtx1); + if (need_rNrm) + ureg_LRP(ureg, r[3], _XXXX(_CONST(30)), vs->aNrm, vs->aNrm1); + vs->aVtx = ureg_src(r[2]); + vs->aNrm = ureg_src(r[3]); + } + + if (key->vertexblend) { + struct ureg_src cWM[4]; + + for (i = 224; i <= 255; ++i) + ureg_DECL_constant(ureg, i); + + /* translate world matrix index to constant file index */ + if (key->vertexblend_indexed) { + ureg_MAD(ureg, tmp, vs->aInd, ureg_imm1f(ureg, 4.0f), ureg_imm1f(ureg, 224.0f)); + ureg_ARL(ureg, AR, ureg_src(tmp)); + } + for (i = 0; i < key->vertexblend; ++i) { + for (c = 0; c < 4; ++c) { + cWM[c] = ureg_src_register(TGSI_FILE_CONSTANT, (224 + i * 4) * !key->vertexblend_indexed + c); + if (key->vertexblend_indexed) + cWM[c] = ureg_src_indirect(cWM[c], ureg_scalar(ureg_src(AR), i)); + } + /* multiply by WORLD(index) */ + ureg_MUL(ureg, r[0], _XXXX(vs->aVtx), cWM[0]); + ureg_MAD(ureg, r[0], _YYYY(vs->aVtx), cWM[1], ureg_src(r[0])); + ureg_MAD(ureg, r[0], _ZZZZ(vs->aVtx), cWM[2], ureg_src(r[0])); + ureg_MAD(ureg, r[0], _WWWW(vs->aVtx), cWM[3], ureg_src(r[0])); + + /* accumulate weighted position value */ + if (i) + ureg_MAD(ureg, r[2], ureg_src(r[0]), ureg_scalar(vs->aWgt, i), ureg_src(r[2])); + else + ureg_MUL(ureg, r[2], ureg_src(r[0]), ureg_scalar(vs->aWgt, 0)); + } + /* multiply by VIEW_PROJ */ + ureg_MUL(ureg, r[0], _X(r[2]), _CONST(8)); + ureg_MAD(ureg, r[0], _Y(r[2]), _CONST(9), ureg_src(r[0])); + ureg_MAD(ureg, r[0], _Z(r[2]), _CONST(10), ureg_src(r[0])); + ureg_MAD(ureg, oPos, _W(r[2]), _CONST(11), ureg_src(r[0])); + + if (need_rVtx) + vs->aVtx = ureg_src(r[2]); + } else + if (key->position_t && device->driver_caps.window_space_position_support) { + ureg_MOV(ureg, oPos, vs->aVtx); + } else if (key->position_t) { + /* vs->aVtx contains the coordinates buffer wise. + * later in the pipeline, clipping, viewport and division + * by w (rhw = 1/w) are going to be applied, so do the reverse + * of these transformations (except clipping) to have the good + * position at the end.*/ + ureg_MOV(ureg, tmp, vs->aVtx); + /* X from [X_min, X_min + width] to [-1, 1], same for Y. Z to [0, 1] */ + ureg_SUB(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _CONST(101)); + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _CONST(100)); + ureg_SUB(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm1f(ureg, 1.0f)); + /* Y needs to be reversed */ + ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_negate(ureg_src(tmp))); + /* inverse rhw */ + ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), _W(tmp)); + /* multiply X, Y, Z by w */ + ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _W(tmp)); + ureg_MOV(ureg, oPos, ureg_src(tmp)); + } else { + /* position = vertex * WORLD_VIEW_PROJ */ + ureg_MUL(ureg, r[0], _XXXX(vs->aVtx), _CONST(0)); + ureg_MAD(ureg, r[0], _YYYY(vs->aVtx), _CONST(1), ureg_src(r[0])); + ureg_MAD(ureg, r[0], _ZZZZ(vs->aVtx), _CONST(2), ureg_src(r[0])); + ureg_MAD(ureg, oPos, _WWWW(vs->aVtx), _CONST(3), ureg_src(r[0])); + } + + if (need_rVtx) { + ureg_MUL(ureg, rVtx, _XXXX(vs->aVtx), _CONST(4)); + ureg_MAD(ureg, rVtx, _YYYY(vs->aVtx), _CONST(5), ureg_src(rVtx)); + ureg_MAD(ureg, rVtx, _ZZZZ(vs->aVtx), _CONST(6), ureg_src(rVtx)); + ureg_MAD(ureg, rVtx, _WWWW(vs->aVtx), _CONST(7), ureg_src(rVtx)); + } + if (need_rNrm) { + ureg_MUL(ureg, rNrm, _XXXX(vs->aNrm), _CONST(16)); + ureg_MAD(ureg, rNrm, _YYYY(vs->aNrm), _CONST(17), ureg_src(rNrm)); + ureg_MAD(ureg, rNrm, _ZZZZ(vs->aNrm), _CONST(18), ureg_src(rNrm)); + ureg_normalize3(ureg, rNrm, ureg_src(rNrm), tmp); + } + /* NOTE: don't use vs->aVtx, vs->aNrm after this line */ + + /* === Process point size: + */ + if (key->vertexpointsize) { + struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); +#ifdef NINE_TGSI_LAZY_DEVS + struct ureg_dst tmp_clamp = ureg_DECL_temporary(ureg); + + ureg_MAX(ureg, tmp_clamp, vs->aPsz, _XXXX(cPsz1)); + ureg_MIN(ureg, oPsz, ureg_src(tmp_clamp), _YYYY(cPsz1)); + ureg_release_temporary(ureg, tmp_clamp); +#else + ureg_CLAMP(ureg, oPsz, vs->aPsz, _XXXX(cPsz1), _YYYY(cPsz1)); +#endif + } else if (key->pointscale) { + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); + struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); + struct ureg_src cPsz2 = ureg_DECL_constant(ureg, 27); + + ureg_DP3(ureg, tmp_x, ureg_src(r[1]), ureg_src(r[1])); + ureg_SQRT(ureg, tmp_y, _X(tmp)); + ureg_MAD(ureg, tmp_x, _Y(tmp), _YYYY(cPsz2), _XXXX(cPsz2)); + ureg_MAD(ureg, tmp_x, _Y(tmp), _X(tmp), _WWWW(cPsz1)); + ureg_RCP(ureg, tmp_x, ureg_src(tmp)); + ureg_MUL(ureg, tmp_x, ureg_src(tmp), _ZZZZ(cPsz1)); +#ifdef NINE_TGSI_LAZY_DEVS + struct ureg_dst tmp_clamp = ureg_DECL_temporary(ureg); + + ureg_MAX(ureg, tmp_clamp, _X(tmp), _XXXX(cPsz1)); + ureg_MIN(ureg, oPsz, ureg_src(tmp_clamp), _YYYY(cPsz1)); + ureg_release_temporary(ureg, tmp_clamp); +#else + ureg_CLAMP(ureg, oPsz, _X(tmp), _XXXX(cPsz1), _YYYY(cPsz1)); +#endif + } + + /* Texture coordinate generation: + * XXX: D3DTTFF_PROJECTED, transform matrix + */ + for (i = 0; i < 8; ++i) { + struct ureg_dst dst[5]; + struct ureg_src src; + unsigned c; + const unsigned tci = (key->tc_gen >> (i * 3)) & 0x7; + const unsigned idx = (key->tc_idx >> (i * 3)) & 0x7; + const unsigned dim = (key->tc_dim >> (i * 3)) & 0x7; + + if (tci == NINED3DTSS_TCI_DISABLE) + continue; + oTex[i] = ureg_DECL_output(ureg, texcoord_sn, i); + + if (tci == NINED3DTSS_TCI_PASSTHRU) + vs->aTex[idx] = build_vs_add_input(vs, NINE_DECLUSAGE_TEXCOORD(idx)); + + if (!dim) { + dst[c = 4] = oTex[i]; + } else { + dst[4] = r[5]; + src = ureg_src(dst[4]); + for (c = 0; c < (dim - 1); ++c) + dst[c] = ureg_writemask(tmp, (1 << dim) - 1); + dst[c] = ureg_writemask(oTex[i], (1 << dim) - 1); + } + + switch (tci) { + case NINED3DTSS_TCI_PASSTHRU: + ureg_MOV(ureg, dst[4], vs->aTex[idx]); + break; + case NINED3DTSS_TCI_CAMERASPACENORMAL: + assert(dim <= 3); + ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rNrm)); + ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + break; + case NINED3DTSS_TCI_CAMERASPACEPOSITION: + ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx)); + ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + break; + case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + tmp.WriteMask = TGSI_WRITEMASK_XYZ; + ureg_DP3(ureg, tmp_x, ureg_src(rVtx), ureg_src(rNrm)); + ureg_MUL(ureg, tmp, ureg_src(rNrm), _X(tmp)); + ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_src(tmp)); + ureg_SUB(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx), ureg_src(tmp)); + ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + tmp.WriteMask = TGSI_WRITEMASK_XYZW; + break; + case NINED3DTSS_TCI_SPHEREMAP: + assert(!"TODO"); + break; + default: + break; + } + if (!dim) + continue; + dst[c].WriteMask = ~dst[c].WriteMask; + if (dst[c].WriteMask) + ureg_MOV(ureg, dst[c], src); /* store untransformed components */ + dst[c].WriteMask = ~dst[c].WriteMask; + if (dim > 0) ureg_MUL(ureg, dst[0], _XXXX(src), _CONST(128 + i * 4)); + if (dim > 1) ureg_MAD(ureg, dst[1], _YYYY(src), _CONST(129 + i * 4), ureg_src(tmp)); + if (dim > 2) ureg_MAD(ureg, dst[2], _ZZZZ(src), _CONST(130 + i * 4), ureg_src(tmp)); + if (dim > 3) ureg_MAD(ureg, dst[3], _WWWW(src), _CONST(131 + i * 4), ureg_src(tmp)); + } + + /* === Lighting: + * + * DIRECTIONAL: Light at infinite distance, parallel rays, no attenuation. + * POINT: Finite distance to scene, divergent rays, isotropic, attenuation. + * SPOT: Finite distance, divergent rays, angular dependence, attenuation. + * + * vec3 normal = normalize(in.Normal * NormalMatrix); + * vec3 hitDir = light.direction; + * float atten = 1.0; + * + * if (light.type != DIRECTIONAL) + * { + * vec3 hitVec = light.position - eyeVertex; + * float d = length(hitVec); + * hitDir = hitVec / d; + * atten = 1 / ((light.atten2 * d + light.atten1) * d + light.atten0); + * } + * + * if (light.type == SPOTLIGHT) + * { + * float rho = dp3(-hitVec, light.direction); + * if (rho < cos(light.phi / 2)) + * atten = 0; + * if (rho < cos(light.theta / 2)) + * atten *= pow(some_func(rho), light.falloff); + * } + * + * float nDotHit = dp3_sat(normal, hitVec); + * float powFact = 0.0; + * + * if (nDotHit > 0.0) + * { + * vec3 midVec = normalize(hitDir + eye); + * float nDotMid = dp3_sat(normal, midVec); + * pFact = pow(nDotMid, material.power); + * } + * + * ambient += light.ambient * atten; + * diffuse += light.diffuse * atten * nDotHit; + * specular += light.specular * atten * powFact; + */ + if (key->lighting) { + struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); + + struct ureg_dst rAtt = ureg_writemask(r[1], TGSI_WRITEMASK_W); + struct ureg_dst rHit = ureg_writemask(r[3], TGSI_WRITEMASK_XYZ); + struct ureg_dst rMid = ureg_writemask(r[4], TGSI_WRITEMASK_XYZ); + + struct ureg_dst rCtr = ureg_writemask(r[2], TGSI_WRITEMASK_W); + + struct ureg_dst AL = ureg_writemask(AR, TGSI_WRITEMASK_X); + + /* Light.*.Alpha is not used. */ + struct ureg_dst rD = ureg_writemask(r[5], TGSI_WRITEMASK_XYZ); + struct ureg_dst rA = ureg_writemask(r[6], TGSI_WRITEMASK_XYZ); + struct ureg_dst rS = ureg_writemask(r[7], TGSI_WRITEMASK_XYZ); + + struct ureg_src mtlP = _XXXX(MATERIAL_CONST(4)); + + struct ureg_src cLKind = _XXXX(LIGHT_CONST(0)); + struct ureg_src cLAtt0 = _YYYY(LIGHT_CONST(0)); + struct ureg_src cLAtt1 = _ZZZZ(LIGHT_CONST(0)); + struct ureg_src cLAtt2 = _WWWW(LIGHT_CONST(0)); + struct ureg_src cLColD = _XYZW(LIGHT_CONST(1)); + struct ureg_src cLColS = _XYZW(LIGHT_CONST(2)); + struct ureg_src cLColA = _XYZW(LIGHT_CONST(3)); + struct ureg_src cLPos = _XYZW(LIGHT_CONST(4)); + struct ureg_src cLRng = _WWWW(LIGHT_CONST(4)); + struct ureg_src cLDir = _XYZW(LIGHT_CONST(5)); + struct ureg_src cLFOff = _WWWW(LIGHT_CONST(5)); + struct ureg_src cLTht = _XXXX(LIGHT_CONST(6)); + struct ureg_src cLPhi = _YYYY(LIGHT_CONST(6)); + struct ureg_src cLSDiv = _ZZZZ(LIGHT_CONST(6)); + struct ureg_src cLLast = _WWWW(LIGHT_CONST(7)); + + const unsigned loop_label = l++; + + ureg_MOV(ureg, rCtr, ureg_imm1f(ureg, 32.0f)); /* &lightconst(0) */ + ureg_MOV(ureg, rD, ureg_imm1f(ureg, 0.0f)); + ureg_MOV(ureg, rA, ureg_imm1f(ureg, 0.0f)); + ureg_MOV(ureg, rS, ureg_imm1f(ureg, 0.0f)); + rD = ureg_saturate(rD); + rA = ureg_saturate(rA); + rS = ureg_saturate(rS); + + + /* loop management */ + ureg_BGNLOOP(ureg, &label[loop_label]); + ureg_ARL(ureg, AL, _W(rCtr)); + + /* if (not DIRECTIONAL light): */ + ureg_SNE(ureg, tmp_x, cLKind, ureg_imm1f(ureg, D3DLIGHT_DIRECTIONAL)); + ureg_MOV(ureg, rHit, ureg_negate(cLDir)); + ureg_MOV(ureg, rAtt, ureg_imm1f(ureg, 1.0f)); + ureg_IF(ureg, _X(tmp), &label[l++]); + { + /* hitDir = light.position - eyeVtx + * d = length(hitDir) + * hitDir /= d + */ + ureg_SUB(ureg, rHit, cLPos, ureg_src(rVtx)); + ureg_DP3(ureg, tmp_x, ureg_src(rHit), ureg_src(rHit)); + ureg_RSQ(ureg, tmp_y, _X(tmp)); + ureg_MUL(ureg, rHit, ureg_src(rHit), _Y(tmp)); /* normalize */ + ureg_MUL(ureg, tmp_x, _X(tmp), _Y(tmp)); /* length */ + + /* att = 1.0 / (light.att0 + (light.att1 + light.att2 * d) * d) */ + ureg_MAD(ureg, rAtt, _X(tmp), cLAtt2, cLAtt1); + ureg_MAD(ureg, rAtt, _X(tmp), _W(rAtt), cLAtt0); + ureg_RCP(ureg, rAtt, _W(rAtt)); + /* cut-off if distance exceeds Light.Range */ + ureg_SLT(ureg, tmp_x, _X(tmp), cLRng); + ureg_MUL(ureg, rAtt, _W(rAtt), _X(tmp)); + } + ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg)); + ureg_ENDIF(ureg); + + /* if (SPOT light) */ + ureg_SEQ(ureg, tmp_x, cLKind, ureg_imm1f(ureg, D3DLIGHT_SPOT)); + ureg_IF(ureg, _X(tmp), &label[l++]); + { + /* rho = dp3(-hitDir, light.spotDir) + * + * if (rho > light.ctht2) NOTE: 0 <= phi <= pi, 0 <= theta <= phi + * spotAtt = 1 + * else + * if (rho <= light.cphi2) + * spotAtt = 0 + * else + * spotAtt = (rho - light.cphi2) / (light.ctht2 - light.cphi2) ^ light.falloff + */ + ureg_DP3(ureg, tmp_y, ureg_negate(ureg_src(rHit)), cLDir); /* rho */ + ureg_SUB(ureg, tmp_x, _Y(tmp), cLPhi); + ureg_MUL(ureg, tmp_x, _X(tmp), cLSDiv); + ureg_POW(ureg, tmp_x, _X(tmp), cLFOff); /* spotAtten */ + ureg_SGE(ureg, tmp_z, _Y(tmp), cLTht); /* if inside theta && phi */ + ureg_SGE(ureg, tmp_y, _Y(tmp), cLPhi); /* if inside phi */ + ureg_MAD(ureg, ureg_saturate(tmp_x), _X(tmp), _Y(tmp), _Z(tmp)); + ureg_MUL(ureg, rAtt, _W(rAtt), _X(tmp)); + } + ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg)); + ureg_ENDIF(ureg); + + /* directional factors, let's not use LIT because of clarity */ + ureg_DP3(ureg, ureg_saturate(tmp_x), ureg_src(rNrm), ureg_src(rHit)); + ureg_MOV(ureg, tmp_y, ureg_imm1f(ureg, 0.0f)); + ureg_IF(ureg, _X(tmp), &label[l++]); + { + /* midVec = normalize(hitDir + eyeDir) */ + if (key->localviewer) { + ureg_normalize3(ureg, rMid, ureg_src(rVtx), tmp); + ureg_ADD(ureg, rMid, ureg_src(rHit), ureg_negate(ureg_src(rMid))); + } else { + ureg_ADD(ureg, rMid, ureg_src(rHit), ureg_imm3f(ureg, 0.0f, 0.0f, 1.0f)); + } + ureg_normalize3(ureg, rMid, ureg_src(rMid), tmp); + ureg_DP3(ureg, ureg_saturate(tmp_y), ureg_src(rNrm), ureg_src(rMid)); + ureg_POW(ureg, tmp_y, _Y(tmp), mtlP); + + ureg_MUL(ureg, tmp_x, _W(rAtt), _X(tmp)); /* dp3(normal,hitDir) * att */ + ureg_MUL(ureg, tmp_y, _W(rAtt), _Y(tmp)); /* power factor * att */ + ureg_MAD(ureg, rD, cLColD, _X(tmp), ureg_src(rD)); /* accumulate diffuse */ + ureg_MAD(ureg, rS, cLColS, _Y(tmp), ureg_src(rS)); /* accumulate specular */ + } + ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg)); + ureg_ENDIF(ureg); + + ureg_MAD(ureg, rA, cLColA, _W(rAtt), ureg_src(rA)); /* accumulate ambient */ + + /* break if this was the last light */ + ureg_IF(ureg, cLLast, &label[l++]); + ureg_BRK(ureg); + ureg_ENDIF(ureg); + ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg)); + + ureg_ADD(ureg, rCtr, _W(rCtr), ureg_imm1f(ureg, 8.0f)); + ureg_fixup_label(ureg, label[loop_label], ureg_get_instruction_number(ureg)); + ureg_ENDLOOP(ureg, &label[loop_label]); + + /* Set alpha factors of illumination to 1.0 for the multiplications. */ + rD.WriteMask = TGSI_WRITEMASK_W; rD.Saturate = 0; + rS.WriteMask = TGSI_WRITEMASK_W; rS.Saturate = 0; + rA.WriteMask = TGSI_WRITEMASK_W; rA.Saturate = 0; + ureg_MOV(ureg, rD, ureg_imm1f(ureg, 1.0f)); + ureg_MOV(ureg, rS, ureg_imm1f(ureg, 1.0f)); + + /* Apply to material: + * + * oCol[0] = (material.emissive + material.ambient * rs.ambient) + + * material.ambient * ambient + + * material.diffuse * diffuse + + * oCol[1] = material.specular * specular; + */ + if (key->mtl_emissive == 0 && key->mtl_ambient == 0) { + ureg_MOV(ureg, rA, ureg_imm1f(ureg, 1.0f)); + ureg_MAD(ureg, tmp, ureg_src(rA), vs->mtlA, _CONST(19)); + } else { + ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(rA), _CONST(25)); + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), vs->mtlA, ureg_src(tmp), vs->mtlE); + ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W ), vs->mtlA, vs->mtlE); + } + ureg_MAD(ureg, rCol[0], ureg_src(rD), vs->mtlD, ureg_src(tmp)); + ureg_MUL(ureg, rCol[1], ureg_src(rS), vs->mtlS); + } else + /* COLOR */ + if (key->darkness) { + if (key->mtl_emissive == 0 && key->mtl_ambient == 0) { + ureg_MAD(ureg, rCol[0], vs->mtlD, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), _CONST(19)); + } else { + ureg_MAD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_XYZ), vs->mtlA, _CONST(25), vs->mtlE); + ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), vs->mtlA, vs->mtlE); + ureg_ADD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_W), vs->mtlD, _W(tmp)); + } + ureg_MUL(ureg, rCol[1], ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), vs->mtlS); + } else { + ureg_MOV(ureg, rCol[0], vs->aCol[0]); + ureg_MOV(ureg, rCol[1], vs->aCol[1]); + } + + /* === Process fog. + * + * exp(x) = ex2(log2(e) * x) + */ + if (key->fog_mode) { + /* Fog doesn't affect alpha, TODO: combine with light code output */ + ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), _W(rCol[0])); + ureg_MOV(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_W), _W(rCol[1])); + + if (key->position_t) { + ureg_MOV(ureg, ureg_saturate(tmp_x), ureg_scalar(vs->aCol[1], TGSI_SWIZZLE_W)); + } else + if (key->fog_range) { + ureg_DP3(ureg, tmp_x, ureg_src(rVtx), ureg_src(rVtx)); + ureg_RSQ(ureg, tmp_z, _X(tmp)); + ureg_MUL(ureg, tmp_z, _Z(tmp), _X(tmp)); + } else { + ureg_MOV(ureg, tmp_z, ureg_abs(_Z(rVtx))); + } + + if (key->fog_mode == D3DFOG_EXP) { + ureg_MUL(ureg, tmp_x, _Z(tmp), _ZZZZ(_CONST(28))); + ureg_MUL(ureg, tmp_x, _X(tmp), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, tmp_x, _X(tmp)); + } else + if (key->fog_mode == D3DFOG_EXP2) { + ureg_MUL(ureg, tmp_x, _Z(tmp), _ZZZZ(_CONST(28))); + ureg_MUL(ureg, tmp_x, _X(tmp), _X(tmp)); + ureg_MUL(ureg, tmp_x, _X(tmp), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, tmp_x, _X(tmp)); + } else + if (key->fog_mode == D3DFOG_LINEAR && !key->position_t) { + ureg_SUB(ureg, tmp_x, _XXXX(_CONST(28)), _Z(tmp)); + ureg_MUL(ureg, ureg_saturate(tmp_x), _X(tmp), _YYYY(_CONST(28))); + } + ureg_MOV(ureg, oFog, _X(tmp)); + ureg_LRP(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[0]), _CONST(29)); + ureg_LRP(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[1]), _CONST(29)); + } + + if (key->position_t && device->driver_caps.window_space_position_support) + ureg_property_vs_window_space_position(ureg, TRUE); + + ureg_END(ureg); + nine_ureg_tgsi_dump(ureg, FALSE); + return ureg_create_shader_and_destroy(ureg, device->pipe); +} + +/* PS FF constants layout: + * + * CONST[ 0.. 7] stage[i].D3DTSS_CONSTANT + * CONST[ 8..15].x___ stage[i].D3DTSS_BUMPENVMAT00 + * CONST[ 8..15]._y__ stage[i].D3DTSS_BUMPENVMAT01 + * CONST[ 8..15].__z_ stage[i].D3DTSS_BUMPENVMAT10 + * CONST[ 8..15].___w stage[i].D3DTSS_BUMPENVMAT11 + * CONST[16..19].x_z_ stage[i].D3DTSS_BUMPENVLSCALE + * CONST[17..19]._y_w stage[i].D3DTSS_BUMPENVLOFFSET + * + * CONST[20] D3DRS_TEXTUREFACTOR + * CONST[21] D3DRS_FOGCOLOR + * CONST[22].x___ RS.FogEnd + * CONST[22]._y__ 1.0f / (RS.FogEnd - RS.FogStart) + * CONST[22].__z_ RS.FogDensity + */ +struct ps_build_ctx +{ + struct ureg_program *ureg; + + struct ureg_src vC[2]; /* DIFFUSE, SPECULAR */ + struct ureg_src vT[8]; /* TEXCOORD[i] */ + struct ureg_dst r[6]; /* TEMPs */ + struct ureg_dst rCur; /* D3DTA_CURRENT */ + struct ureg_dst rMod; + struct ureg_src rCurSrc; + struct ureg_dst rTmp; /* D3DTA_TEMP */ + struct ureg_src rTmpSrc; + struct ureg_dst rTex; + struct ureg_src rTexSrc; + struct ureg_src cBEM[8]; + struct ureg_src s[8]; + + struct { + unsigned index; + unsigned index_pre_mod; + unsigned num_regs; + } stage; +}; + +static struct ureg_src +ps_get_ts_arg(struct ps_build_ctx *ps, unsigned ta) +{ + struct ureg_src reg; + + switch (ta & D3DTA_SELECTMASK) { + case D3DTA_CONSTANT: + reg = ureg_DECL_constant(ps->ureg, ps->stage.index); + break; + case D3DTA_CURRENT: + reg = (ps->stage.index == ps->stage.index_pre_mod) ? ureg_src(ps->rMod) : ps->rCurSrc; + break; + case D3DTA_DIFFUSE: + reg = ureg_DECL_fs_input(ps->ureg, TGSI_SEMANTIC_COLOR, 0, TGSI_INTERPOLATE_PERSPECTIVE); + break; + case D3DTA_SPECULAR: + reg = ureg_DECL_fs_input(ps->ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE); + break; + case D3DTA_TEMP: + reg = ps->rTmpSrc; + break; + case D3DTA_TEXTURE: + reg = ps->rTexSrc; + break; + case D3DTA_TFACTOR: + reg = ureg_DECL_constant(ps->ureg, 20); + break; + default: + assert(0); + reg = ureg_src_undef(); + break; + } + if (ta & D3DTA_COMPLEMENT) { + struct ureg_dst dst = ps->r[ps->stage.num_regs++]; + ureg_SUB(ps->ureg, dst, ureg_imm1f(ps->ureg, 1.0f), reg); + reg = ureg_src(dst); + } + if (ta & D3DTA_ALPHAREPLICATE) + reg = _WWWW(reg); + return reg; +} + +static struct ureg_dst +ps_get_ts_dst(struct ps_build_ctx *ps, unsigned ta) +{ + assert(!(ta & (D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE))); + + switch (ta & D3DTA_SELECTMASK) { + case D3DTA_CURRENT: + return ps->rCur; + case D3DTA_TEMP: + return ps->rTmp; + default: + assert(0); + return ureg_dst_undef(); + } +} + +static uint8_t ps_d3dtop_args_mask(D3DTEXTUREOP top) +{ + switch (top) { + case D3DTOP_DISABLE: + return 0x0; + case D3DTOP_SELECTARG1: + case D3DTOP_PREMODULATE: + return 0x2; + case D3DTOP_SELECTARG2: + return 0x4; + case D3DTOP_MULTIPLYADD: + case D3DTOP_LERP: + return 0x7; + default: + return 0x6; + } +} + +static INLINE boolean +is_MOV_no_op(struct ureg_dst dst, struct ureg_src src) +{ + return !dst.WriteMask || + (dst.File == src.File && + dst.Index == src.Index && + !dst.Indirect && + !dst.Saturate && + !src.Indirect && + !src.Negate && + !src.Absolute && + (!(dst.WriteMask & TGSI_WRITEMASK_X) || (src.SwizzleX == TGSI_SWIZZLE_X)) && + (!(dst.WriteMask & TGSI_WRITEMASK_Y) || (src.SwizzleY == TGSI_SWIZZLE_Y)) && + (!(dst.WriteMask & TGSI_WRITEMASK_Z) || (src.SwizzleZ == TGSI_SWIZZLE_Z)) && + (!(dst.WriteMask & TGSI_WRITEMASK_W) || (src.SwizzleW == TGSI_SWIZZLE_W))); + +} + +static void +ps_do_ts_op(struct ps_build_ctx *ps, unsigned top, struct ureg_dst dst, struct ureg_src *arg) +{ + struct ureg_program *ureg = ps->ureg; + struct ureg_dst tmp = ps->r[ps->stage.num_regs]; + struct ureg_dst tmp2 = ps->r[ps->stage.num_regs+1]; + struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + + tmp.WriteMask = dst.WriteMask; + + if (top != D3DTOP_SELECTARG1 && top != D3DTOP_SELECTARG2 && + top != D3DTOP_MODULATE && top != D3DTOP_PREMODULATE && + top != D3DTOP_BLENDDIFFUSEALPHA && top != D3DTOP_BLENDTEXTUREALPHA && + top != D3DTOP_BLENDFACTORALPHA && top != D3DTOP_BLENDCURRENTALPHA && + top != D3DTOP_BUMPENVMAP && top != D3DTOP_BUMPENVMAPLUMINANCE && + top != D3DTOP_LERP) + dst = ureg_saturate(dst); + + switch (top) { + case D3DTOP_SELECTARG1: + if (!is_MOV_no_op(dst, arg[1])) + ureg_MOV(ureg, dst, arg[1]); + break; + case D3DTOP_SELECTARG2: + if (!is_MOV_no_op(dst, arg[2])) + ureg_MOV(ureg, dst, arg[2]); + break; + case D3DTOP_MODULATE: + ureg_MUL(ureg, dst, arg[1], arg[2]); + break; + case D3DTOP_MODULATE2X: + ureg_MUL(ureg, tmp, arg[1], arg[2]); + ureg_ADD(ureg, dst, ureg_src(tmp), ureg_src(tmp)); + break; + case D3DTOP_MODULATE4X: + ureg_MUL(ureg, tmp, arg[1], arg[2]); + ureg_MUL(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 4.0f)); + break; + case D3DTOP_ADD: + ureg_ADD(ureg, dst, arg[1], arg[2]); + break; + case D3DTOP_ADDSIGNED: + ureg_ADD(ureg, tmp, arg[1], arg[2]); + ureg_SUB(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 0.5f)); + break; + case D3DTOP_ADDSIGNED2X: + ureg_ADD(ureg, tmp, arg[1], arg[2]); + ureg_MAD(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 2.0f), ureg_imm1f(ureg, -1.0f)); + break; + case D3DTOP_SUBTRACT: + ureg_SUB(ureg, dst, arg[1], arg[2]); + break; + case D3DTOP_ADDSMOOTH: + ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), arg[1]); + ureg_MAD(ureg, dst, ureg_src(tmp), arg[2], arg[1]); + break; + case D3DTOP_BLENDDIFFUSEALPHA: + ureg_LRP(ureg, dst, _WWWW(ps->vC[0]), arg[1], arg[2]); + break; + case D3DTOP_BLENDTEXTUREALPHA: + /* XXX: alpha taken from previous stage, texture or result ? */ + ureg_LRP(ureg, dst, _W(ps->rTex), arg[1], arg[2]); + break; + case D3DTOP_BLENDFACTORALPHA: + ureg_LRP(ureg, dst, _WWWW(_CONST(20)), arg[1], arg[2]); + break; + case D3DTOP_BLENDTEXTUREALPHAPM: + ureg_SUB(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), _W(ps->rTex)); + ureg_MAD(ureg, dst, arg[2], _X(tmp), arg[1]); + break; + case D3DTOP_BLENDCURRENTALPHA: + ureg_LRP(ureg, dst, _WWWW(ps->rCurSrc), arg[1], arg[2]); + break; + case D3DTOP_PREMODULATE: + ureg_MOV(ureg, dst, arg[1]); + ps->stage.index_pre_mod = ps->stage.index + 1; + break; + case D3DTOP_MODULATEALPHA_ADDCOLOR: + ureg_MAD(ureg, dst, _WWWW(arg[1]), arg[2], arg[1]); + break; + case D3DTOP_MODULATECOLOR_ADDALPHA: + ureg_MAD(ureg, dst, arg[1], arg[2], _WWWW(arg[1])); + break; + case D3DTOP_MODULATEINVALPHA_ADDCOLOR: + ureg_SUB(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), _WWWW(arg[1])); + ureg_MAD(ureg, dst, _X(tmp), arg[2], arg[1]); + break; + case D3DTOP_MODULATEINVCOLOR_ADDALPHA: + ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), arg[1]); + ureg_MAD(ureg, dst, ureg_src(tmp), arg[2], _WWWW(arg[1])); + break; + case D3DTOP_BUMPENVMAP: + break; + case D3DTOP_BUMPENVMAPLUMINANCE: + break; + case D3DTOP_DOTPRODUCT3: + ureg_SUB(ureg, tmp, arg[1], ureg_imm4f(ureg,0.5,0.5,0.5,0.5)); + ureg_SUB(ureg, tmp2, arg[2] , ureg_imm4f(ureg,0.5,0.5,0.5,0.5)); + ureg_DP3(ureg, tmp, ureg_src(tmp), ureg_src(tmp2)); + ureg_MUL(ureg, ureg_saturate(dst), ureg_src(tmp), ureg_imm4f(ureg,4.0,4.0,4.0,4.0)); + break; + case D3DTOP_MULTIPLYADD: + ureg_MAD(ureg, dst, arg[2], arg[0], arg[1]); + break; + case D3DTOP_LERP: + ureg_LRP(ureg, dst, arg[1], arg[2], arg[0]); + break; + case D3DTOP_DISABLE: + /* no-op ? */ + break; + default: + assert(!"invalid D3DTOP"); + break; + } +} + +static void * +nine_ff_build_ps(struct NineDevice9 *device, struct nine_ff_ps_key *key) +{ + struct ps_build_ctx ps; + struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + struct ureg_dst oCol; + unsigned i, s; + const unsigned texcoord_sn = get_texcoord_sn(device->screen); + + memset(&ps, 0, sizeof(ps)); + ps.ureg = ureg; + ps.stage.index_pre_mod = -1; + + ps.vC[0] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 0, TGSI_INTERPOLATE_PERSPECTIVE); + + /* Declare all TEMPs we might need, serious drivers have a register allocator. */ + for (i = 0; i < Elements(ps.r); ++i) + ps.r[i] = ureg_DECL_local_temporary(ureg); + ps.rCur = ps.r[0]; + ps.rTmp = ps.r[1]; + ps.rTex = ps.r[2]; + ps.rCurSrc = ureg_src(ps.rCur); + ps.rTmpSrc = ureg_src(ps.rTmp); + ps.rTexSrc = ureg_src(ps.rTex); + + for (s = 0; s < 8; ++s) { + ps.s[s] = ureg_src_undef(); + + if (key->ts[s].colorop != D3DTOP_DISABLE) { + if (key->ts[s].colorarg0 == D3DTA_SPECULAR || + key->ts[s].colorarg1 == D3DTA_SPECULAR || + key->ts[s].colorarg2 == D3DTA_SPECULAR) + ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE); + + if (key->ts[s].colorarg0 == D3DTA_TEXTURE || + key->ts[s].colorarg1 == D3DTA_TEXTURE || + key->ts[s].colorarg2 == D3DTA_TEXTURE) { + ps.s[s] = ureg_DECL_sampler(ureg, s); + ps.vT[s] = ureg_DECL_fs_input(ureg, texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + } + if (s && (key->ts[s - 1].colorop == D3DTOP_PREMODULATE || + key->ts[s - 1].alphaop == D3DTOP_PREMODULATE)) + ps.s[s] = ureg_DECL_sampler(ureg, s); + } + + if (key->ts[s].alphaop != D3DTOP_DISABLE) { + if (key->ts[s].alphaarg0 == D3DTA_SPECULAR || + key->ts[s].alphaarg1 == D3DTA_SPECULAR || + key->ts[s].alphaarg2 == D3DTA_SPECULAR) + ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE); + + if (key->ts[s].alphaarg0 == D3DTA_TEXTURE || + key->ts[s].alphaarg1 == D3DTA_TEXTURE || + key->ts[s].alphaarg2 == D3DTA_TEXTURE) { + ps.s[s] = ureg_DECL_sampler(ureg, s); + ps.vT[s] = ureg_DECL_fs_input(ureg, texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + } + } + } + if (key->specular) + ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE); + + oCol = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + + if (key->ts[0].colorop == D3DTOP_DISABLE && + key->ts[0].alphaop == D3DTOP_DISABLE) + ureg_MOV(ureg, ps.rCur, ps.vC[0]); + /* Or is it undefined then ? */ + + /* Run stages. + */ + for (s = 0; s < 8; ++s) { + unsigned colorarg[3]; + unsigned alphaarg[3]; + const uint8_t used_c = ps_d3dtop_args_mask(key->ts[s].colorop); + const uint8_t used_a = ps_d3dtop_args_mask(key->ts[s].alphaop); + struct ureg_dst dst; + struct ureg_src arg[3]; + + if (key->ts[s].colorop == D3DTOP_DISABLE && + key->ts[s].alphaop == D3DTOP_DISABLE) + continue; + ps.stage.index = s; + ps.stage.num_regs = 3; + + DBG("STAGE[%u]: colorop=%s alphaop=%s\n", s, + nine_D3DTOP_to_str(key->ts[s].colorop), + nine_D3DTOP_to_str(key->ts[s].alphaop)); + + if (!ureg_src_is_undef(ps.s[s])) { + unsigned target; + switch (key->ts[s].textarget) { + case 0: target = TGSI_TEXTURE_1D; break; + case 1: target = TGSI_TEXTURE_2D; break; + case 2: target = TGSI_TEXTURE_3D; break; + case 3: target = TGSI_TEXTURE_CUBE; break; + /* this is a 2 bit bitfield, do I really need a default case ? */ + } + + /* sample the texture */ + if (key->ts[s].colorop == D3DTOP_BUMPENVMAP || + key->ts[s].colorop == D3DTOP_BUMPENVMAPLUMINANCE) { + } + if (key->ts[s].projected) + ureg_TXP(ureg, ps.rTex, target, ps.vT[s], ps.s[s]); + else + ureg_TEX(ureg, ps.rTex, target, ps.vT[s], ps.s[s]); + } + + if (s == 0 && + (key->ts[0].resultarg != 0 /* not current */ || + key->ts[0].colorop == D3DTOP_DISABLE || + key->ts[0].alphaop == D3DTOP_DISABLE || + key->ts[0].colorarg0 == D3DTA_CURRENT || + key->ts[0].colorarg1 == D3DTA_CURRENT || + key->ts[0].colorarg2 == D3DTA_CURRENT || + key->ts[0].alphaarg0 == D3DTA_CURRENT || + key->ts[0].alphaarg1 == D3DTA_CURRENT || + key->ts[0].alphaarg2 == D3DTA_CURRENT) + ) { + /* Initialize D3DTA_CURRENT. + * (Yes we can do this before the loop but not until + * NVE4 has an instruction scheduling pass.) + */ + ureg_MOV(ureg, ps.rCur, ps.vC[0]); + } + + dst = ps_get_ts_dst(&ps, key->ts[s].resultarg ? D3DTA_TEMP : D3DTA_CURRENT); + + if (ps.stage.index_pre_mod == ps.stage.index) { + ps.rMod = ps.r[ps.stage.num_regs++]; + ureg_MUL(ureg, ps.rMod, ps.rCurSrc, ps.rTexSrc); + } + + colorarg[0] = (key->ts[s].colorarg0 | ((key->colorarg_b4[0] >> s) << 4) | ((key->colorarg_b5[0] >> s) << 5)) & 0x3f; + colorarg[1] = (key->ts[s].colorarg1 | ((key->colorarg_b4[1] >> s) << 4) | ((key->colorarg_b5[1] >> s) << 5)) & 0x3f; + colorarg[2] = (key->ts[s].colorarg2 | ((key->colorarg_b4[2] >> s) << 4) | ((key->colorarg_b5[2] >> s) << 5)) & 0x3f; + alphaarg[0] = (key->ts[s].alphaarg0 | ((key->alphaarg_b4[0] >> s) << 4)) & 0x1f; + alphaarg[1] = (key->ts[s].alphaarg1 | ((key->alphaarg_b4[1] >> s) << 4)) & 0x1f; + alphaarg[2] = (key->ts[s].alphaarg2 | ((key->alphaarg_b4[2] >> s) << 4)) & 0x1f; + + if (key->ts[s].colorop != key->ts[s].alphaop || + colorarg[0] != alphaarg[0] || + colorarg[1] != alphaarg[1] || + colorarg[2] != alphaarg[2]) + dst.WriteMask = TGSI_WRITEMASK_XYZ; + + if (used_c & 0x1) arg[0] = ps_get_ts_arg(&ps, colorarg[0]); + if (used_c & 0x2) arg[1] = ps_get_ts_arg(&ps, colorarg[1]); + if (used_c & 0x4) arg[2] = ps_get_ts_arg(&ps, colorarg[2]); + ps_do_ts_op(&ps, key->ts[s].colorop, dst, arg); + + if (dst.WriteMask != TGSI_WRITEMASK_XYZW) { + dst.WriteMask = TGSI_WRITEMASK_W; + + if (used_a & 0x1) arg[0] = ps_get_ts_arg(&ps, alphaarg[0]); + if (used_a & 0x2) arg[1] = ps_get_ts_arg(&ps, alphaarg[1]); + if (used_a & 0x4) arg[2] = ps_get_ts_arg(&ps, alphaarg[2]); + ps_do_ts_op(&ps, key->ts[s].alphaop, dst, arg); + } + } + + if (key->specular) + ureg_ADD(ureg, ps.rCur, ps.rCurSrc, ps.vC[1]); + + /* Fog. + */ + if (key->fog_mode) { + struct ureg_src vPos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0, TGSI_INTERPOLATE_LINEAR); + struct ureg_dst rFog = ureg_writemask(ps.rTmp, TGSI_WRITEMASK_X); + if (key->fog_mode == D3DFOG_EXP) { + ureg_MUL(ureg, rFog, _ZZZZ(vPos), _ZZZZ(_CONST(22))); + ureg_MUL(ureg, rFog, _X(rFog), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, rFog, _X(rFog)); + } else + if (key->fog_mode == D3DFOG_EXP2) { + ureg_MUL(ureg, rFog, _ZZZZ(vPos), _ZZZZ(_CONST(22))); + ureg_MUL(ureg, rFog, _X(rFog), _X(rFog)); + ureg_MUL(ureg, rFog, _X(rFog), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, rFog, _X(rFog)); + } else + if (key->fog_mode == D3DFOG_LINEAR) { + ureg_SUB(ureg, rFog, _XXXX(_CONST(22)), _ZZZZ(vPos)); + ureg_MUL(ureg, ureg_saturate(rFog), _X(rFog), _YYYY(_CONST(22))); + } + ureg_LRP(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_XYZ), _X(rFog), ps.rCurSrc, _CONST(21)); + ureg_MOV(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_W), ps.rCurSrc); + } else + if (key->fog) { + struct ureg_src vFog = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_FOG, 0, TGSI_INTERPOLATE_PERSPECTIVE); + ureg_LRP(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_XYZ), _XXXX(vFog), ps.rCurSrc, _CONST(21)); + ureg_MOV(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_W), ps.rCurSrc); + } else { + ureg_MOV(ureg, oCol, ps.rCurSrc); + } + + ureg_END(ureg); + nine_ureg_tgsi_dump(ureg, FALSE); + return ureg_create_shader_and_destroy(ureg, device->pipe); +} + +static struct NineVertexShader9 * +nine_ff_get_vs(struct NineDevice9 *device) +{ + const struct nine_state *state = &device->state; + struct NineVertexShader9 *vs; + enum pipe_error err; + struct vs_build_ctx bld; + struct nine_ff_vs_key key; + unsigned s; + + assert(sizeof(key) <= sizeof(key.value32)); + + memset(&key, 0, sizeof(key)); + memset(&bld, 0, sizeof(bld)); + + bld.key = &key; + + /* FIXME: this shouldn't be NULL, but it is on init */ + if (state->vdecl) { + if (state->vdecl->usage_map[NINE_DECLUSAGE_POSITIONT] != 0xff) + key.position_t = 1; + if (state->vdecl->usage_map[NINE_DECLUSAGE_COLOR(0)] == 0xff) + key.color0in_one = 1; + if (state->vdecl->usage_map[NINE_DECLUSAGE_COLOR(1)] == 0xff) + key.color1in_one = 1; + if (state->vdecl->usage_map[NINE_DECLUSAGE_PSIZE] != 0xff) + key.vertexpointsize = 1; + } + if (!key.vertexpointsize) + key.pointscale = !!state->rs[D3DRS_POINTSCALEENABLE]; + + key.lighting = !!state->rs[D3DRS_LIGHTING] && state->ff.num_lights_active; + key.darkness = !!state->rs[D3DRS_LIGHTING] && !state->ff.num_lights_active; + if (key.position_t) { + key.darkness = 0; /* |= key.lighting; */ /* XXX ? */ + key.lighting = 0; + } + if ((key.lighting | key.darkness) && state->rs[D3DRS_COLORVERTEX]) { + key.mtl_diffuse = state->rs[D3DRS_DIFFUSEMATERIALSOURCE]; + key.mtl_ambient = state->rs[D3DRS_AMBIENTMATERIALSOURCE]; + key.mtl_specular = state->rs[D3DRS_SPECULARMATERIALSOURCE]; + key.mtl_emissive = state->rs[D3DRS_EMISSIVEMATERIALSOURCE]; + } + key.fog_mode = state->rs[D3DRS_FOGENABLE] ? state->rs[D3DRS_FOGVERTEXMODE] : 0; + if (key.fog_mode) + key.fog_range = !key.position_t && state->rs[D3DRS_RANGEFOGENABLE]; + + if (state->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) { + key.vertexblend_indexed = !!state->rs[D3DRS_INDEXEDVERTEXBLENDENABLE]; + + switch (state->rs[D3DRS_VERTEXBLEND]) { + case D3DVBF_0WEIGHTS: key.vertexblend = key.vertexblend_indexed; break; + case D3DVBF_1WEIGHTS: key.vertexblend = 2; break; + case D3DVBF_2WEIGHTS: key.vertexblend = 3; break; + case D3DVBF_3WEIGHTS: key.vertexblend = 4; break; + case D3DVBF_TWEENING: key.vertextween = 1; break; + default: + assert(!"invalid D3DVBF"); + break; + } + } + + for (s = 0; s < 8; ++s) { + if (state->ff.tex_stage[s][D3DTSS_COLOROP] == D3DTOP_DISABLE && + state->ff.tex_stage[s][D3DTSS_ALPHAOP] == D3DTOP_DISABLE) + break; + key.tc_idx |= (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] & 7) << (s * 3); + if (!key.position_t) { + unsigned gen = (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1; + unsigned dim = MIN2(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7, 4); + key.tc_gen |= gen << (s * 3); + key.tc_dim |= dim << (s * 3); + } else { + key.tc_gen |= NINED3DTSS_TCI_PASSTHRU << (s * 3); + } + } + + vs = util_hash_table_get(device->ff.ht_vs, &key); + if (vs) + return vs; + NineVertexShader9_new(device, &vs, NULL, nine_ff_build_vs(device, &bld)); + + nine_ff_prune_vs(device); + if (vs) { + unsigned n; + + memcpy(&vs->ff_key, &key, sizeof(vs->ff_key)); + + err = util_hash_table_set(device->ff.ht_vs, &vs->ff_key, vs); + assert(err == PIPE_OK); + device->ff.num_vs++; + NineUnknown_ConvertRefToBind(NineUnknown(vs)); + + vs->num_inputs = bld.num_inputs; + for (n = 0; n < bld.num_inputs; ++n) + vs->input_map[n].ndecl = bld.input[n]; + + vs->position_t = key.position_t; + vs->point_size = key.vertexpointsize | key.pointscale; + } + return vs; +} + +static struct NinePixelShader9 * +nine_ff_get_ps(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct NinePixelShader9 *ps; + enum pipe_error err; + struct nine_ff_ps_key key; + unsigned s; + + assert(sizeof(key) <= sizeof(key.value32)); + + memset(&key, 0, sizeof(key)); + for (s = 0; s < 8; ++s) { + key.ts[s].colorop = state->ff.tex_stage[s][D3DTSS_COLOROP]; + key.ts[s].alphaop = state->ff.tex_stage[s][D3DTSS_ALPHAOP]; + /* MSDN says D3DTOP_DISABLE disables this and all subsequent stages. */ + /* ALPHAOP cannot be disabled if COLOROP is enabled. */ + if (key.ts[s].colorop == D3DTOP_DISABLE) { + key.ts[s].alphaop = D3DTOP_DISABLE; /* DISABLE == 1, avoid degenerate keys */ + break; + } + if (!state->texture[s] && + state->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE) { + /* This should also disable the stage. */ + key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE; + break; + } + if (key.ts[s].colorop != D3DTOP_DISABLE) { + uint8_t used_c = ps_d3dtop_args_mask(key.ts[s].colorop); + if (used_c & 0x1) key.ts[s].colorarg0 = state->ff.tex_stage[s][D3DTSS_COLORARG0]; + if (used_c & 0x2) key.ts[s].colorarg1 = state->ff.tex_stage[s][D3DTSS_COLORARG1]; + if (used_c & 0x4) key.ts[s].colorarg2 = state->ff.tex_stage[s][D3DTSS_COLORARG2]; + if (used_c & 0x1) key.colorarg_b4[0] |= (state->ff.tex_stage[s][D3DTSS_COLORARG0] >> 4) << s; + if (used_c & 0x1) key.colorarg_b5[0] |= (state->ff.tex_stage[s][D3DTSS_COLORARG0] >> 5) << s; + if (used_c & 0x2) key.colorarg_b4[1] |= (state->ff.tex_stage[s][D3DTSS_COLORARG1] >> 4) << s; + if (used_c & 0x2) key.colorarg_b5[1] |= (state->ff.tex_stage[s][D3DTSS_COLORARG1] >> 5) << s; + if (used_c & 0x4) key.colorarg_b4[2] |= (state->ff.tex_stage[s][D3DTSS_COLORARG2] >> 4) << s; + if (used_c & 0x4) key.colorarg_b5[2] |= (state->ff.tex_stage[s][D3DTSS_COLORARG2] >> 5) << s; + } + if (key.ts[s].alphaop != D3DTOP_DISABLE) { + uint8_t used_a = ps_d3dtop_args_mask(key.ts[s].alphaop); + if (used_a & 0x1) key.ts[s].alphaarg0 = state->ff.tex_stage[s][D3DTSS_ALPHAARG0]; + if (used_a & 0x2) key.ts[s].alphaarg1 = state->ff.tex_stage[s][D3DTSS_ALPHAARG1]; + if (used_a & 0x4) key.ts[s].alphaarg2 = state->ff.tex_stage[s][D3DTSS_ALPHAARG2]; + if (used_a & 0x1) key.alphaarg_b4[0] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG0] >> 4) << s; + if (used_a & 0x2) key.alphaarg_b4[1] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG1] >> 4) << s; + if (used_a & 0x4) key.alphaarg_b4[2] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG2] >> 4) << s; + } + key.ts[s].resultarg = state->ff.tex_stage[s][D3DTSS_RESULTARG] == D3DTA_TEMP; + + key.ts[s].projected = !!(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED); + + if (state->texture[s]) { + switch (state->texture[s]->base.type) { + case D3DRTYPE_TEXTURE: key.ts[s].textarget = 1; break; + case D3DRTYPE_VOLUMETEXTURE: key.ts[s].textarget = 2; break; + case D3DRTYPE_CUBETEXTURE: key.ts[s].textarget = 3; break; + default: + assert(!"unexpected texture type"); + break; + } + } else { + key.ts[s].textarget = 1; + } + } + for (; s < 8; ++s) + key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE; + if (state->rs[D3DRS_FOGENABLE]) + key.fog_mode = state->rs[D3DRS_FOGTABLEMODE]; + + ps = util_hash_table_get(device->ff.ht_ps, &key); + if (ps) + return ps; + NinePixelShader9_new(device, &ps, NULL, nine_ff_build_ps(device, &key)); + + nine_ff_prune_ps(device); + if (ps) { + memcpy(&ps->ff_key, &key, sizeof(ps->ff_key)); + + err = util_hash_table_set(device->ff.ht_ps, &ps->ff_key, ps); + assert(err == PIPE_OK); + device->ff.num_ps++; + NineUnknown_ConvertRefToBind(NineUnknown(ps)); + + ps->rt_mask = 0x1; + } + return ps; +} + +#define GET_D3DTS(n) nine_state_access_transform(state, D3DTS_##n, FALSE) +#define IS_D3DTS_DIRTY(s,n) ((s)->ff.changed.transform[(D3DTS_##n) / 32] & (1 << ((D3DTS_##n) % 32))) +static void +nine_ff_load_vs_transforms(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + D3DMATRIX T; + D3DMATRIX *M = (D3DMATRIX *)device->ff.vs_const; + unsigned i; + + /* TODO: make this nicer, and only upload the ones we need */ + /* TODO: use ff.vs_const as storage of W, V, P matrices */ + + if (IS_D3DTS_DIRTY(state, WORLD) || + IS_D3DTS_DIRTY(state, VIEW) || + IS_D3DTS_DIRTY(state, PROJECTION)) { + /* WVP, WV matrices */ + nine_d3d_matrix_matrix_mul(&M[1], GET_D3DTS(WORLD), GET_D3DTS(VIEW)); + nine_d3d_matrix_matrix_mul(&M[0], &M[1], GET_D3DTS(PROJECTION)); + + /* normal matrix == transpose(inverse(WV)) */ + nine_d3d_matrix_inverse_3x3(&T, &M[1]); + nine_d3d_matrix_transpose(&M[4], &T); + + /* VP matrix */ + nine_d3d_matrix_matrix_mul(&M[2], GET_D3DTS(VIEW), GET_D3DTS(PROJECTION)); + + /* V and W matrix */ + M[3] = *GET_D3DTS(VIEW); + M[56] = *GET_D3DTS(WORLD); + } + + if (state->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) { + /* load other world matrices */ + for (i = 1; i <= 7; ++i) + M[56 + i] = *GET_D3DTS(WORLDMATRIX(i)); + } + + device->ff.vs_const[30 * 4] = asfloat(state->rs[D3DRS_TWEENFACTOR]); +} + +static void +nine_ff_load_lights(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const; + unsigned l; + + if (state->changed.group & NINE_STATE_FF_MATERIAL) { + const D3DMATERIAL9 *mtl = &state->ff.material; + + memcpy(&dst[20], &mtl->Diffuse, 4 * sizeof(float)); + memcpy(&dst[21], &mtl->Ambient, 4 * sizeof(float)); + memcpy(&dst[22], &mtl->Specular, 4 * sizeof(float)); + dst[23].x = mtl->Power; + memcpy(&dst[24], &mtl->Emissive, 4 * sizeof(float)); + d3dcolor_to_rgba(&dst[25].x, state->rs[D3DRS_AMBIENT]); + dst[19].x = dst[25].x * mtl->Ambient.r + mtl->Emissive.r; + dst[19].y = dst[25].y * mtl->Ambient.g + mtl->Emissive.g; + dst[19].z = dst[25].z * mtl->Ambient.b + mtl->Emissive.b; + dst[19].w = mtl->Ambient.a + mtl->Emissive.a; + } + + if (!(state->changed.group & NINE_STATE_FF_LIGHTING)) + return; + + for (l = 0; l < state->ff.num_lights_active; ++l) { + const D3DLIGHT9 *light = &state->ff.light[state->ff.active_light[l]]; + + dst[32 + l * 8].x = light->Type; + dst[32 + l * 8].y = light->Attenuation0; + dst[32 + l * 8].z = light->Attenuation1; + dst[32 + l * 8].w = light->Attenuation2; + memcpy(&dst[33 + l * 8].x, &light->Diffuse, sizeof(light->Diffuse)); + memcpy(&dst[34 + l * 8].x, &light->Specular, sizeof(light->Specular)); + memcpy(&dst[35 + l * 8].x, &light->Ambient, sizeof(light->Ambient)); + nine_d3d_vector4_matrix_mul((D3DVECTOR *)&dst[36 + l * 8].x, &light->Position, GET_D3DTS(VIEW)); + nine_d3d_vector3_matrix_mul((D3DVECTOR *)&dst[37 + l * 8].x, &light->Direction, GET_D3DTS(VIEW)); + dst[36 + l * 8].w = light->Type == D3DLIGHT_DIRECTIONAL ? 1e9f : light->Range; + dst[37 + l * 8].w = light->Falloff; + dst[38 + l * 8].x = cosf(light->Theta * 0.5f); + dst[38 + l * 8].y = cosf(light->Phi * 0.5f); + dst[38 + l * 8].z = 1.0f / (dst[38 + l * 8].x - dst[38 + l * 8].y); + dst[39 + l * 8].w = (l + 1) == state->ff.num_lights_active; + } +} + +static void +nine_ff_load_point_and_fog_params(struct NineDevice9 *device) +{ + const struct nine_state *state = &device->state; + struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const; + + if (!(state->changed.group & NINE_STATE_FF_OTHER)) + return; + dst[26].x = asfloat(state->rs[D3DRS_POINTSIZE_MIN]); + dst[26].y = asfloat(state->rs[D3DRS_POINTSIZE_MAX]); + dst[26].z = asfloat(state->rs[D3DRS_POINTSIZE]); + dst[26].w = asfloat(state->rs[D3DRS_POINTSCALE_A]); + dst[27].x = asfloat(state->rs[D3DRS_POINTSCALE_B]); + dst[27].y = asfloat(state->rs[D3DRS_POINTSCALE_C]); + dst[28].x = asfloat(state->rs[D3DRS_FOGEND]); + dst[28].y = 1.0f / (asfloat(state->rs[D3DRS_FOGEND]) - asfloat(state->rs[D3DRS_FOGSTART])); + if (isinf(dst[28].y)) + dst[28].y = 0.0f; + dst[28].z = asfloat(state->rs[D3DRS_FOGDENSITY]); + d3dcolor_to_rgba(&dst[29].x, state->rs[D3DRS_FOGCOLOR]); +} + +static void +nine_ff_load_tex_matrices(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + D3DMATRIX *M = (D3DMATRIX *)device->ff.vs_const; + unsigned s; + + if (!(state->ff.changed.transform[0] & 0xff0000)) + return; + for (s = 0; s < 8; ++s) { + if (IS_D3DTS_DIRTY(state, TEXTURE0 + s)) + M[32 + s] = *nine_state_access_transform(state, D3DTS_TEXTURE0 + s, FALSE); + } +} + +static void +nine_ff_load_ps_params(struct NineDevice9 *device) +{ + const struct nine_state *state = &device->state; + struct fvec4 *dst = (struct fvec4 *)device->ff.ps_const; + unsigned s; + + if (!(state->changed.group & (NINE_STATE_FF_PSSTAGES | NINE_STATE_FF_OTHER))) + return; + + for (s = 0; s < 8; ++s) + d3dcolor_to_rgba(&dst[s].x, state->ff.tex_stage[s][D3DTSS_CONSTANT]); + + for (s = 0; s < 8; ++s) { + dst[8 + s].x = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT00]); + dst[8 + s].y = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT01]); + dst[8 + s].z = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT10]); + dst[8 + s].w = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT11]); + if (s & 1) { + dst[8 + s / 2].z = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]); + dst[8 + s / 2].w = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]); + } else { + dst[8 + s / 2].x = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]); + dst[8 + s / 2].y = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]); + } + } + + d3dcolor_to_rgba(&dst[20].x, state->rs[D3DRS_TEXTUREFACTOR]); + d3dcolor_to_rgba(&dst[21].x, state->rs[D3DRS_FOGCOLOR]); + dst[22].x = asfloat(state->rs[D3DRS_FOGEND]); + dst[22].y = 1.0f / (asfloat(state->rs[D3DRS_FOGEND]) - asfloat(state->rs[D3DRS_FOGSTART])); + dst[22].z = asfloat(state->rs[D3DRS_FOGDENSITY]); +} + +static void +nine_ff_load_viewport_info(struct NineDevice9 *device) +{ + D3DVIEWPORT9 *viewport = &device->state.viewport; + struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const; + float diffZ = viewport->MaxZ - viewport->MinZ; + + /* Note: the other functions avoids to fill the const again if nothing changed. + * But we don't have much to fill, and adding code to allow that may be complex + * so just fill it always */ + dst[100].x = 2.0f / (float)(viewport->Width); + dst[100].y = 2.0f / (float)(viewport->Height); + dst[100].z = (diffZ == 0.0f) ? 0.0f : (1.0f / diffZ); + dst[101].x = (float)(viewport->X); + dst[101].y = (float)(viewport->Y); + dst[101].z = (float)(viewport->MinZ); +} + +void +nine_ff_update(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + + DBG("vs=%p ps=%p\n", device->state.vs, device->state.ps); + + /* NOTE: the only reference belongs to the hash table */ + if (!device->state.vs) + device->ff.vs = nine_ff_get_vs(device); + if (!device->state.ps) + device->ff.ps = nine_ff_get_ps(device); + + if (!device->state.vs) { + if (device->state.ff.clobber.vs_const) { + device->state.ff.clobber.vs_const = FALSE; + device->state.changed.group |= + NINE_STATE_FF_VSTRANSF | + NINE_STATE_FF_MATERIAL | + NINE_STATE_FF_LIGHTING | + NINE_STATE_FF_OTHER; + device->state.ff.changed.transform[0] |= 0xff000c; + device->state.ff.changed.transform[8] |= 0xff; + } + nine_ff_load_vs_transforms(device); + nine_ff_load_tex_matrices(device); + nine_ff_load_lights(device); + nine_ff_load_point_and_fog_params(device); + nine_ff_load_viewport_info(device); + + memset(state->ff.changed.transform, 0, sizeof(state->ff.changed.transform)); + + device->state.changed.group |= NINE_STATE_VS; + device->state.changed.group |= NINE_STATE_VS_CONST; + + if (device->prefer_user_constbuf) { + struct pipe_context *pipe = device->pipe; + struct pipe_constant_buffer cb; + cb.buffer_offset = 0; + cb.buffer = NULL; + cb.user_buffer = device->ff.vs_const; + cb.buffer_size = NINE_FF_NUM_VS_CONST * 4 * sizeof(float); + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); + } else { + struct pipe_box box; + u_box_1d(0, NINE_FF_NUM_VS_CONST * 4 * sizeof(float), &box); + pipe->transfer_inline_write(pipe, device->constbuf_vs, 0, + 0, &box, + device->ff.vs_const, 0, 0); + nine_ranges_insert(&device->state.changed.vs_const_f, 0, NINE_FF_NUM_VS_CONST, + &device->range_pool); + } + } + + if (!device->state.ps) { + if (device->state.ff.clobber.ps_const) { + device->state.ff.clobber.ps_const = FALSE; + device->state.changed.group |= + NINE_STATE_FF_PSSTAGES | + NINE_STATE_FF_OTHER; + } + nine_ff_load_ps_params(device); + + device->state.changed.group |= NINE_STATE_PS; + device->state.changed.group |= NINE_STATE_PS_CONST; + + if (device->prefer_user_constbuf) { + struct pipe_context *pipe = device->pipe; + struct pipe_constant_buffer cb; + cb.buffer_offset = 0; + cb.buffer = NULL; + cb.user_buffer = device->ff.ps_const; + cb.buffer_size = NINE_FF_NUM_PS_CONST * 4 * sizeof(float); + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); + } else { + struct pipe_box box; + u_box_1d(0, NINE_FF_NUM_PS_CONST * 4 * sizeof(float), &box); + pipe->transfer_inline_write(pipe, device->constbuf_ps, 0, + 0, &box, + device->ff.ps_const, 0, 0); + nine_ranges_insert(&device->state.changed.ps_const_f, 0, NINE_FF_NUM_PS_CONST, + &device->range_pool); + } + } + + device->state.changed.group &= ~NINE_STATE_FF; +} + + +boolean +nine_ff_init(struct NineDevice9 *device) +{ + device->ff.ht_vs = util_hash_table_create(nine_ff_vs_key_hash, + nine_ff_vs_key_comp); + device->ff.ht_ps = util_hash_table_create(nine_ff_ps_key_hash, + nine_ff_ps_key_comp); + + device->ff.ht_fvf = util_hash_table_create(nine_ff_fvf_key_hash, + nine_ff_fvf_key_comp); + + device->ff.vs_const = CALLOC(NINE_FF_NUM_VS_CONST, 4 * sizeof(float)); + device->ff.ps_const = CALLOC(NINE_FF_NUM_PS_CONST, 4 * sizeof(float)); + + return device->ff.ht_vs && device->ff.ht_ps && + device->ff.ht_fvf && + device->ff.vs_const && device->ff.ps_const; +} + +static enum pipe_error nine_ff_ht_delete_cb(void *key, void *value, void *data) +{ + NineUnknown_Unbind(NineUnknown(value)); + return PIPE_OK; +} + +void +nine_ff_fini(struct NineDevice9 *device) +{ + if (device->ff.ht_vs) { + util_hash_table_foreach(device->ff.ht_vs, nine_ff_ht_delete_cb, NULL); + util_hash_table_destroy(device->ff.ht_vs); + } + if (device->ff.ht_ps) { + util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL); + util_hash_table_destroy(device->ff.ht_ps); + } + if (device->ff.ht_fvf) { + util_hash_table_foreach(device->ff.ht_fvf, nine_ff_ht_delete_cb, NULL); + util_hash_table_destroy(device->ff.ht_fvf); + } + device->ff.vs = NULL; /* destroyed by unbinding from hash table */ + device->ff.ps = NULL; + + FREE(device->ff.vs_const); + FREE(device->ff.ps_const); +} + +static void +nine_ff_prune_vs(struct NineDevice9 *device) +{ + if (device->ff.num_vs > 100) { + /* could destroy the bound one here, so unbind */ + device->pipe->bind_vs_state(device->pipe, NULL); + util_hash_table_foreach(device->ff.ht_vs, nine_ff_ht_delete_cb, NULL); + util_hash_table_clear(device->ff.ht_vs); + device->ff.num_vs = 0; + device->state.changed.group |= NINE_STATE_VS; + } +} +static void +nine_ff_prune_ps(struct NineDevice9 *device) +{ + if (device->ff.num_ps > 100) { + /* could destroy the bound one here, so unbind */ + device->pipe->bind_fs_state(device->pipe, NULL); + util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL); + util_hash_table_clear(device->ff.ht_ps); + device->ff.num_ps = 0; + device->state.changed.group |= NINE_STATE_PS; + } +} + +/* ========================================================================== */ + +/* Matrix multiplication: + * + * in memory: 0 1 2 3 (row major) + * 4 5 6 7 + * 8 9 a b + * c d e f + * + * cA cB cC cD + * r0 = (r0 * cA) (r0 * cB) . . + * r1 = (r1 * cA) (r1 * cB) + * r2 = (r2 * cA) . + * r3 = (r3 * cA) . + * + * r: (11) (12) (13) (14) + * (21) (22) (23) (24) + * (31) (32) (33) (34) + * (41) (42) (43) (44) + * l: (11 12 13 14) + * (21 22 23 24) + * (31 32 33 34) + * (41 42 43 44) + * + * v: (x y z 1 ) + * + * t.xyzw = MUL(v.xxxx, r[0]); + * t.xyzw = MAD(v.yyyy, r[1], t.xyzw); + * t.xyzw = MAD(v.zzzz, r[2], t.xyzw); + * v.xyzw = MAD(v.wwww, r[3], t.xyzw); + * + * v.x = DP4(v, c[0]); + * v.y = DP4(v, c[1]); + * v.z = DP4(v, c[2]); + * v.w = DP4(v, c[3]) = 1 + */ + +/* +static void +nine_D3DMATRIX_print(const D3DMATRIX *M) +{ + DBG("\n(%f %f %f %f)\n" + "(%f %f %f %f)\n" + "(%f %f %f %f)\n" + "(%f %f %f %f)\n", + M->m[0][0], M->m[0][1], M->m[0][2], M->m[0][3], + M->m[1][0], M->m[1][1], M->m[1][2], M->m[1][3], + M->m[2][0], M->m[2][1], M->m[2][2], M->m[2][3], + M->m[3][0], M->m[3][1], M->m[3][2], M->m[3][3]); +} +*/ + +static INLINE float +nine_DP4_row_col(const D3DMATRIX *A, int r, const D3DMATRIX *B, int c) +{ + return A->m[r][0] * B->m[0][c] + + A->m[r][1] * B->m[1][c] + + A->m[r][2] * B->m[2][c] + + A->m[r][3] * B->m[3][c]; +} + +static INLINE float +nine_DP4_vec_col(const D3DVECTOR *v, const D3DMATRIX *M, int c) +{ + return v->x * M->m[0][c] + + v->y * M->m[1][c] + + v->z * M->m[2][c] + + 1.0f * M->m[3][c]; +} + +static INLINE float +nine_DP3_vec_col(const D3DVECTOR *v, const D3DMATRIX *M, int c) +{ + return v->x * M->m[0][c] + + v->y * M->m[1][c] + + v->z * M->m[2][c]; +} + +void +nine_d3d_matrix_matrix_mul(D3DMATRIX *D, const D3DMATRIX *L, const D3DMATRIX *R) +{ + D->_11 = nine_DP4_row_col(L, 0, R, 0); + D->_12 = nine_DP4_row_col(L, 0, R, 1); + D->_13 = nine_DP4_row_col(L, 0, R, 2); + D->_14 = nine_DP4_row_col(L, 0, R, 3); + + D->_21 = nine_DP4_row_col(L, 1, R, 0); + D->_22 = nine_DP4_row_col(L, 1, R, 1); + D->_23 = nine_DP4_row_col(L, 1, R, 2); + D->_24 = nine_DP4_row_col(L, 1, R, 3); + + D->_31 = nine_DP4_row_col(L, 2, R, 0); + D->_32 = nine_DP4_row_col(L, 2, R, 1); + D->_33 = nine_DP4_row_col(L, 2, R, 2); + D->_34 = nine_DP4_row_col(L, 2, R, 3); + + D->_41 = nine_DP4_row_col(L, 3, R, 0); + D->_42 = nine_DP4_row_col(L, 3, R, 1); + D->_43 = nine_DP4_row_col(L, 3, R, 2); + D->_44 = nine_DP4_row_col(L, 3, R, 3); +} + +void +nine_d3d_vector4_matrix_mul(D3DVECTOR *d, const D3DVECTOR *v, const D3DMATRIX *M) +{ + d->x = nine_DP4_vec_col(v, M, 0); + d->y = nine_DP4_vec_col(v, M, 1); + d->z = nine_DP4_vec_col(v, M, 2); +} + +void +nine_d3d_vector3_matrix_mul(D3DVECTOR *d, const D3DVECTOR *v, const D3DMATRIX *M) +{ + d->x = nine_DP3_vec_col(v, M, 0); + d->y = nine_DP3_vec_col(v, M, 1); + d->z = nine_DP3_vec_col(v, M, 2); +} + +void +nine_d3d_matrix_transpose(D3DMATRIX *D, const D3DMATRIX *M) +{ + unsigned i, j; + for (i = 0; i < 4; ++i) + for (j = 0; j < 4; ++j) + D->m[i][j] = M->m[j][i]; +} + +#define _M_ADD_PROD_1i_2j_3k_4l(i,j,k,l) do { \ + float t = M->_1##i * M->_2##j * M->_3##k * M->_4##l; \ + if (t > 0.0f) pos += t; else neg += t; } while(0) + +#define _M_SUB_PROD_1i_2j_3k_4l(i,j,k,l) do { \ + float t = M->_1##i * M->_2##j * M->_3##k * M->_4##l; \ + if (t > 0.0f) neg -= t; else pos -= t; } while(0) +float +nine_d3d_matrix_det(const D3DMATRIX *M) +{ + float pos = 0.0f; + float neg = 0.0f; + + _M_ADD_PROD_1i_2j_3k_4l(1, 2, 3, 4); + _M_ADD_PROD_1i_2j_3k_4l(1, 3, 4, 2); + _M_ADD_PROD_1i_2j_3k_4l(1, 4, 2, 3); + + _M_ADD_PROD_1i_2j_3k_4l(2, 1, 4, 3); + _M_ADD_PROD_1i_2j_3k_4l(2, 3, 1, 4); + _M_ADD_PROD_1i_2j_3k_4l(2, 4, 3, 1); + + _M_ADD_PROD_1i_2j_3k_4l(3, 1, 2, 4); + _M_ADD_PROD_1i_2j_3k_4l(3, 2, 4, 1); + _M_ADD_PROD_1i_2j_3k_4l(3, 4, 1, 2); + + _M_ADD_PROD_1i_2j_3k_4l(4, 1, 3, 2); + _M_ADD_PROD_1i_2j_3k_4l(4, 2, 1, 3); + _M_ADD_PROD_1i_2j_3k_4l(4, 3, 2, 1); + + _M_SUB_PROD_1i_2j_3k_4l(1, 2, 4, 3); + _M_SUB_PROD_1i_2j_3k_4l(1, 3, 2, 4); + _M_SUB_PROD_1i_2j_3k_4l(1, 4, 3, 2); + + _M_SUB_PROD_1i_2j_3k_4l(2, 1, 3, 4); + _M_SUB_PROD_1i_2j_3k_4l(2, 3, 4, 1); + _M_SUB_PROD_1i_2j_3k_4l(2, 4, 1, 3); + + _M_SUB_PROD_1i_2j_3k_4l(3, 1, 4, 2); + _M_SUB_PROD_1i_2j_3k_4l(3, 2, 1, 4); + _M_SUB_PROD_1i_2j_3k_4l(3, 4, 2, 1); + + _M_SUB_PROD_1i_2j_3k_4l(4, 1, 2, 3); + _M_SUB_PROD_1i_2j_3k_4l(4, 2, 3, 1); + _M_SUB_PROD_1i_2j_3k_4l(4, 3, 1, 2); + + return pos + neg; +} + +/* XXX: Probably better to just use src/mesa/math/m_matrix.c because + * I have no idea where this code came from. + */ +void +nine_d3d_matrix_inverse(D3DMATRIX *D, const D3DMATRIX *M) +{ + int i, k; + float det; + + D->m[0][0] = + M->m[1][1] * M->m[2][2] * M->m[3][3] - + M->m[1][1] * M->m[3][2] * M->m[2][3] - + M->m[1][2] * M->m[2][1] * M->m[3][3] + + M->m[1][2] * M->m[3][1] * M->m[2][3] + + M->m[1][3] * M->m[2][1] * M->m[3][2] - + M->m[1][3] * M->m[3][1] * M->m[2][2]; + + D->m[0][1] = + -M->m[0][1] * M->m[2][2] * M->m[3][3] + + M->m[0][1] * M->m[3][2] * M->m[2][3] + + M->m[0][2] * M->m[2][1] * M->m[3][3] - + M->m[0][2] * M->m[3][1] * M->m[2][3] - + M->m[0][3] * M->m[2][1] * M->m[3][2] + + M->m[0][3] * M->m[3][1] * M->m[2][2]; + + D->m[0][2] = + M->m[0][1] * M->m[1][2] * M->m[3][3] - + M->m[0][1] * M->m[3][2] * M->m[1][3] - + M->m[0][2] * M->m[1][1] * M->m[3][3] + + M->m[0][2] * M->m[3][1] * M->m[1][3] + + M->m[0][3] * M->m[1][1] * M->m[3][2] - + M->m[0][3] * M->m[3][1] * M->m[1][2]; + + D->m[0][3] = + -M->m[0][1] * M->m[1][2] * M->m[2][3] + + M->m[0][1] * M->m[2][2] * M->m[1][3] + + M->m[0][2] * M->m[1][1] * M->m[2][3] - + M->m[0][2] * M->m[2][1] * M->m[1][3] - + M->m[0][3] * M->m[1][1] * M->m[2][2] + + M->m[0][3] * M->m[2][1] * M->m[1][2]; + + D->m[1][0] = + -M->m[1][0] * M->m[2][2] * M->m[3][3] + + M->m[1][0] * M->m[3][2] * M->m[2][3] + + M->m[1][2] * M->m[2][0] * M->m[3][3] - + M->m[1][2] * M->m[3][0] * M->m[2][3] - + M->m[1][3] * M->m[2][0] * M->m[3][2] + + M->m[1][3] * M->m[3][0] * M->m[2][2]; + + D->m[1][1] = + M->m[0][0] * M->m[2][2] * M->m[3][3] - + M->m[0][0] * M->m[3][2] * M->m[2][3] - + M->m[0][2] * M->m[2][0] * M->m[3][3] + + M->m[0][2] * M->m[3][0] * M->m[2][3] + + M->m[0][3] * M->m[2][0] * M->m[3][2] - + M->m[0][3] * M->m[3][0] * M->m[2][2]; + + D->m[1][2] = + -M->m[0][0] * M->m[1][2] * M->m[3][3] + + M->m[0][0] * M->m[3][2] * M->m[1][3] + + M->m[0][2] * M->m[1][0] * M->m[3][3] - + M->m[0][2] * M->m[3][0] * M->m[1][3] - + M->m[0][3] * M->m[1][0] * M->m[3][2] + + M->m[0][3] * M->m[3][0] * M->m[1][2]; + + D->m[1][3] = + M->m[0][0] * M->m[1][2] * M->m[2][3] - + M->m[0][0] * M->m[2][2] * M->m[1][3] - + M->m[0][2] * M->m[1][0] * M->m[2][3] + + M->m[0][2] * M->m[2][0] * M->m[1][3] + + M->m[0][3] * M->m[1][0] * M->m[2][2] - + M->m[0][3] * M->m[2][0] * M->m[1][2]; + + D->m[2][0] = + M->m[1][0] * M->m[2][1] * M->m[3][3] - + M->m[1][0] * M->m[3][1] * M->m[2][3] - + M->m[1][1] * M->m[2][0] * M->m[3][3] + + M->m[1][1] * M->m[3][0] * M->m[2][3] + + M->m[1][3] * M->m[2][0] * M->m[3][1] - + M->m[1][3] * M->m[3][0] * M->m[2][1]; + + D->m[2][1] = + -M->m[0][0] * M->m[2][1] * M->m[3][3] + + M->m[0][0] * M->m[3][1] * M->m[2][3] + + M->m[0][1] * M->m[2][0] * M->m[3][3] - + M->m[0][1] * M->m[3][0] * M->m[2][3] - + M->m[0][3] * M->m[2][0] * M->m[3][1] + + M->m[0][3] * M->m[3][0] * M->m[2][1]; + + D->m[2][2] = + M->m[0][0] * M->m[1][1] * M->m[3][3] - + M->m[0][0] * M->m[3][1] * M->m[1][3] - + M->m[0][1] * M->m[1][0] * M->m[3][3] + + M->m[0][1] * M->m[3][0] * M->m[1][3] + + M->m[0][3] * M->m[1][0] * M->m[3][1] - + M->m[0][3] * M->m[3][0] * M->m[1][1]; + + D->m[2][3] = + -M->m[0][0] * M->m[1][1] * M->m[2][3] + + M->m[0][0] * M->m[2][1] * M->m[1][3] + + M->m[0][1] * M->m[1][0] * M->m[2][3] - + M->m[0][1] * M->m[2][0] * M->m[1][3] - + M->m[0][3] * M->m[1][0] * M->m[2][1] + + M->m[0][3] * M->m[2][0] * M->m[1][1]; + + D->m[3][0] = + -M->m[1][0] * M->m[2][1] * M->m[3][2] + + M->m[1][0] * M->m[3][1] * M->m[2][2] + + M->m[1][1] * M->m[2][0] * M->m[3][2] - + M->m[1][1] * M->m[3][0] * M->m[2][2] - + M->m[1][2] * M->m[2][0] * M->m[3][1] + + M->m[1][2] * M->m[3][0] * M->m[2][1]; + + D->m[3][1] = + M->m[0][0] * M->m[2][1] * M->m[3][2] - + M->m[0][0] * M->m[3][1] * M->m[2][2] - + M->m[0][1] * M->m[2][0] * M->m[3][2] + + M->m[0][1] * M->m[3][0] * M->m[2][2] + + M->m[0][2] * M->m[2][0] * M->m[3][1] - + M->m[0][2] * M->m[3][0] * M->m[2][1]; + + D->m[3][2] = + -M->m[0][0] * M->m[1][1] * M->m[3][2] + + M->m[0][0] * M->m[3][1] * M->m[1][2] + + M->m[0][1] * M->m[1][0] * M->m[3][2] - + M->m[0][1] * M->m[3][0] * M->m[1][2] - + M->m[0][2] * M->m[1][0] * M->m[3][1] + + M->m[0][2] * M->m[3][0] * M->m[1][1]; + + D->m[3][3] = + M->m[0][0] * M->m[1][1] * M->m[2][2] - + M->m[0][0] * M->m[2][1] * M->m[1][2] - + M->m[0][1] * M->m[1][0] * M->m[2][2] + + M->m[0][1] * M->m[2][0] * M->m[1][2] + + M->m[0][2] * M->m[1][0] * M->m[2][1] - + M->m[0][2] * M->m[2][0] * M->m[1][1]; + + det = + M->m[0][0] * D->m[0][0] + + M->m[1][0] * D->m[0][1] + + M->m[2][0] * D->m[0][2] + + M->m[3][0] * D->m[0][3]; + + det = 1.0 / det; + + for (i = 0; i < 4; i++) + for (k = 0; k < 4; k++) + D->m[i][k] *= det; + +#ifdef DEBUG + { + D3DMATRIX I; + + nine_d3d_matrix_matrix_mul(&I, D, M); + + for (i = 0; i < 4; ++i) + for (k = 0; k < 4; ++k) + if (fabsf(I.m[i][k] - (float)(i == k)) > 1e-3) + DBG("Matrix inversion check FAILED !\n"); + } +#endif +} + +/* TODO: don't use 4x4 inverse, unless this gets all nicely inlined ? */ +void +nine_d3d_matrix_inverse_3x3(D3DMATRIX *D, const D3DMATRIX *M) +{ + D3DMATRIX T; + unsigned i, j; + + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + T.m[i][j] = M->m[i][j]; + for (i = 0; i < 3; ++i) { + T.m[i][3] = 0.0f; + T.m[3][i] = 0.0f; + } + T.m[3][3] = 1.0f; + + nine_d3d_matrix_inverse(D, &T); +} diff --git a/src/gallium/state_trackers/nine/nine_ff.h b/src/gallium/state_trackers/nine/nine_ff.h new file mode 100644 index 00000000000..7cefa65b1c4 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_ff.h @@ -0,0 +1,32 @@ + +#ifndef _NINE_FF_H_ +#define _NINE_FF_H_ + +#include "device9.h" + +boolean nine_ff_init(struct NineDevice9 *); +void nine_ff_fini(struct NineDevice9 *); + +void nine_ff_update(struct NineDevice9 *); + +void +nine_d3d_matrix_matrix_mul(D3DMATRIX *, const D3DMATRIX *, const D3DMATRIX *); + +void +nine_d3d_vector4_matrix_mul(D3DVECTOR *, const D3DVECTOR *, const D3DMATRIX *); +void +nine_d3d_vector3_matrix_mul(D3DVECTOR *, const D3DVECTOR *, const D3DMATRIX *); + +float +nine_d3d_matrix_det(const D3DMATRIX *); + +void +nine_d3d_matrix_inverse(D3DMATRIX *, const D3DMATRIX *); + +void +nine_d3d_matrix_inverse_3x3(D3DMATRIX *, const D3DMATRIX *); + +void +nine_d3d_matrix_transpose(D3DMATRIX *, const D3DMATRIX *); + +#endif /* _NINE_FF_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_helpers.c b/src/gallium/state_trackers/nine/nine_helpers.c new file mode 100644 index 00000000000..ed179f9aedc --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_helpers.c @@ -0,0 +1,100 @@ +/* + * Copyright 2013 Christoph Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_helpers.h" + +static struct nine_range * +nine_range_pool_more(struct nine_range_pool *pool) +{ + struct nine_range *r = MALLOC(64 * sizeof(struct nine_range)); + int i; + assert(!pool->free); + + if (pool->num_slabs == pool->num_slabs_max) { + unsigned p = pool->num_slabs_max; + unsigned n = pool->num_slabs_max * 2; + if (!n) + n = 4; + pool->slabs = REALLOC(pool->slabs, + p * sizeof(struct nine_range *), + n * sizeof(struct nine_range *)); + pool->num_slabs_max = n; + } + pool->free = pool->slabs[pool->num_slabs++] = r; + + for (i = 0; i < 63; ++i, r = r->next) + r->next = (struct nine_range *) + ((uint8_t *)r + sizeof(struct nine_range)); + r->next = NULL; + + return pool->free; +} + +static INLINE struct nine_range * +nine_range_pool_get(struct nine_range_pool *pool, int16_t bgn, int16_t end) +{ + struct nine_range *r = pool->free; + if (!r) + r = nine_range_pool_more(pool); + assert(r); + pool->free = r->next; + r->bgn = bgn; + r->end = end; + return r; +} + +static INLINE void +nine_ranges_coalesce(struct nine_range *r, struct nine_range_pool *pool) +{ + struct nine_range *n; + + while (r->next && r->end >= r->next->bgn) { + n = r->next->next; + r->end = (r->end >= r->next->end) ? r->end : r->next->end; + nine_range_pool_put(pool, r->next); + r->next = n; + } +} + +void +nine_ranges_insert(struct nine_range **head, int16_t bgn, int16_t end, + struct nine_range_pool *pool) +{ + struct nine_range *r, **pn = head; + + for (r = *head; r && bgn > r->end; pn = &r->next, r = r->next); + + if (!r || end < r->bgn) { + *pn = nine_range_pool_get(pool, bgn, end); + (*pn)->next = r; + } else + if (bgn < r->bgn) { + r->bgn = bgn; + if (end > r->end) + r->end = end; + nine_ranges_coalesce(r, pool); + } else + if (end > r->end) { + r->end = end; + nine_ranges_coalesce(r, pool); + } +} diff --git a/src/gallium/state_trackers/nine/nine_helpers.h b/src/gallium/state_trackers/nine/nine_helpers.h new file mode 100644 index 00000000000..e81db79a4ae --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_helpers.h @@ -0,0 +1,176 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_HELPERS_H_ +#define _NINE_HELPERS_H_ + +#include "iunknown.h" +#include "nine_lock.h" + +/* + * Note: we use these function rather than the MIN2, MAX2, CLAMP macros to + * avoid evaluating arguments (which are often function calls) more than once. + */ + +static inline unsigned _min(unsigned a, unsigned b) +{ + return (a < b) ? a : b; +} + + +/* Sshhh ... */ +#define nine_reference(a, b) _nine_reference((void **)(a), (b)) + +static inline void _nine_reference(void **ref, void *ptr) +{ + if (*ref != ptr) { + if (*ref) + NineUnknown_Release(*ref); + if (ptr) + NineUnknown_AddRef(ptr); + *ref = ptr; + } +} + +#define nine_reference_set(a, b) _nine_reference_set((void **)(a), (b)) + +static inline void _nine_reference_set(void **ref, void *ptr) +{ + *ref = ptr; + if (ptr) + NineUnknown_AddRef(ptr); +} + +#define nine_bind(a, b) _nine_bind((void **)(a), (b)) + +static inline void _nine_bind(void **dst, void *obj) +{ + if (*dst != obj) { + if (*dst) + NineUnknown_Unbind(*dst); + if (obj) + NineUnknown_Bind(obj); + *dst = obj; + } +} + +#define NINE_DEVICE_CHILD_NEW(nine, out, dev, ...) \ + { \ + struct NineUnknownParams __params; \ + struct Nine##nine *__data; \ + \ + __data = CALLOC_STRUCT(Nine##nine); \ + if (!__data) { return E_OUTOFMEMORY; } \ + \ + __params.vtable = ((dev)->params.BehaviorFlags & D3DCREATE_MULTITHREADED) ? &Lock##nine##_vtable : &Nine##nine##_vtable; \ + __params.guids = Nine##nine##_IIDs; \ + __params.dtor = (void *)Nine##nine##_dtor; \ + __params.container = NULL; \ + __params.device = dev; \ + { \ + HRESULT __hr = Nine##nine##_ctor(__data, &__params, ## __VA_ARGS__); \ + if (FAILED(__hr)) { \ + Nine##nine##_dtor(__data); \ + return __hr; \ + } \ + } \ + \ + *(out) = __data; \ + } \ + return D3D_OK + +#define NINE_NEW(nine, out, lock, ...) \ + { \ + struct NineUnknownParams __params; \ + struct Nine##nine *__data; \ + \ + __data = CALLOC_STRUCT(Nine##nine); \ + if (!__data) { return E_OUTOFMEMORY; } \ + \ + __params.vtable = (lock) ? &Lock##nine##_vtable : &Nine##nine##_vtable; \ + __params.guids = Nine##nine##_IIDs; \ + __params.dtor = (void *)Nine##nine##_dtor; \ + __params.container = NULL; \ + __params.device = NULL; \ + { \ + HRESULT __hr = Nine##nine##_ctor(__data, &__params, ## __VA_ARGS__); \ + if (FAILED(__hr)) { \ + Nine##nine##_dtor(__data); \ + return __hr; \ + } \ + } \ + \ + *(out) = __data; \ + } \ + return D3D_OK + +static INLINE float asfloat(DWORD value) +{ + union { + float f; + DWORD w; + } u; + u.w = value; + return u.f; +} + +#define CHECK_PIPE_RESOURCE_TEMPLATE(t) \ + screen->is_format_supported(screen, (t).format, (t).target, (t).nr_samples, (t).bind) + + +struct nine_range +{ + struct nine_range *next; + int16_t bgn; /* inclusive */ + int16_t end; /* exclusive */ +}; + +/* We won't ever need more than 256 ranges, so just allocate once. */ +struct nine_range_pool +{ + struct nine_range *free; + struct nine_range **slabs; + unsigned num_slabs; + unsigned num_slabs_max; +}; + +static INLINE void +nine_range_pool_put(struct nine_range_pool *pool, struct nine_range *r) +{ + r->next = pool->free; + pool->free = r; +} + +static INLINE void +nine_range_pool_put_chain(struct nine_range_pool *pool, + struct nine_range *head, + struct nine_range *tail) +{ + tail->next = pool->free; + pool->free = head; +} + +void +nine_ranges_insert(struct nine_range **head, int16_t bgn, int16_t end, + struct nine_range_pool *pool); + +#endif /* _NINE_HELPERS_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_lock.c b/src/gallium/state_trackers/nine/nine_lock.c new file mode 100644 index 00000000000..42cbb0589c4 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_lock.c @@ -0,0 +1,3319 @@ +/* + * Copyright 2013 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "authenticatedchannel9.h" +#include "basetexture9.h" +#include "cryptosession9.h" +#include "cubetexture9.h" +#include "device9.h" +#include "device9ex.h" +#include "device9video.h" +#include "indexbuffer9.h" +#include "pixelshader9.h" +#include "query9.h" +#include "resource9.h" +#include "stateblock9.h" +#include "surface9.h" +#include "swapchain9.h" +#include "swapchain9ex.h" +#include "texture9.h" +#include "vertexbuffer9.h" +#include "vertexdeclaration9.h" +#include "vertexshader9.h" +#include "volume9.h" +#include "volumetexture9.h" + +#include "d3d9.h" + +#include "os/os_thread.h" + +/* Global mutex as described by MSDN */ +pipe_static_mutex(d3dlock_global); + +static HRESULT WINAPI +LockAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This, + UINT *pCertificateSize ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineAuthenticatedChannel9_GetCertificateSize(This, pCertificateSize); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineAuthenticatedChannel9_GetCertificate(This, CertifacteSize, ppCertificate); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This, + UINT DataSize, + void *pData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineAuthenticatedChannel9_NegotiateKeyExchange(This, DataSize, pData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + UINT OutputSize, + void *pOutput ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineAuthenticatedChannel9_Query(This, InputSize, pInput, OutputSize, pOutput); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This, + UINT InputSize, + const void *pInput, + D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineAuthenticatedChannel9_Configure(This, InputSize, pInput, pOutput); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DAuthenticatedChannel9Vtbl LockAuthenticatedChannel9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockAuthenticatedChannel9_GetCertificateSize, + (void *)LockAuthenticatedChannel9_GetCertificate, + (void *)LockAuthenticatedChannel9_NegotiateKeyExchange, + (void *)LockAuthenticatedChannel9_Query, + (void *)LockAuthenticatedChannel9_Configure +}; + +#if 0 +static HRESULT WINAPI +LockResource9_GetDevice( struct NineResource9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockResource9_SetPrivateData( struct NineResource9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_SetPrivateData(This, refguid, pData, SizeOfData, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockResource9_GetPrivateData( struct NineResource9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_GetPrivateData(This, refguid, pData, pSizeOfData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockResource9_FreePrivateData( struct NineResource9 *This, + REFGUID refguid ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_FreePrivateData(This, refguid); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static DWORD WINAPI +LockResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_SetPriority(This, PriorityNew); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static DWORD WINAPI +LockResource9_GetPriority( struct NineResource9 *This ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_GetPriority(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static void WINAPI +LockResource9_PreLoad( struct NineResource9 *This ) +{ + pipe_mutex_lock(d3dlock_global); + NineResource9_PreLoad(This); + pipe_mutex_unlock(d3dlock_global); +} +#endif + +#if 0 +static D3DRESOURCETYPE WINAPI +LockResource9_GetType( struct NineResource9 *This ) +{ + D3DRESOURCETYPE r; + pipe_mutex_lock(d3dlock_global); + r = NineResource9_GetType(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static DWORD WINAPI +LockBaseTexture9_SetLOD( struct NineBaseTexture9 *This, + DWORD LODNew ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineBaseTexture9_SetLOD(This, LODNew); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static DWORD WINAPI +LockBaseTexture9_GetLOD( struct NineBaseTexture9 *This ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineBaseTexture9_GetLOD(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static DWORD WINAPI +LockBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineBaseTexture9_GetLevelCount(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, + D3DTEXTUREFILTERTYPE FilterType ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineBaseTexture9_SetAutoGenFilterType(This, FilterType); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static D3DTEXTUREFILTERTYPE WINAPI +LockBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ) +{ + D3DTEXTUREFILTERTYPE r; + pipe_mutex_lock(d3dlock_global); + r = NineBaseTexture9_GetAutoGenFilterType(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static void WINAPI +LockBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) +{ + pipe_mutex_lock(d3dlock_global); + NineBaseTexture9_PreLoad(This); + pipe_mutex_unlock(d3dlock_global); +} + +static void WINAPI +LockBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) +{ + pipe_mutex_lock(d3dlock_global); + NineBaseTexture9_GenerateMipSubLevels(This); + pipe_mutex_unlock(d3dlock_global); +} + +static HRESULT WINAPI +LockCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This, + UINT *pCertificateSize ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_GetCertificateSize(This, pCertificateSize); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_GetCertificate( struct NineCryptoSession9 *This, + UINT CertifacteSize, + BYTE *ppCertificate ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_GetCertificate(This, CertifacteSize, ppCertificate); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This, + UINT DataSize, + void *pData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_NegotiateKeyExchange(This, DataSize, pData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT DstSurfaceSize, + void *pIV ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_EncryptionBlt(This, pSrcSurface, pDstSurface, DstSurfaceSize, pIV); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + IDirect3DSurface9 *pDstSurface, + UINT SrcSurfaceSize, + D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, + void *pContentKey, + void *pIV ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_DecryptionBlt(This, pSrcSurface, pDstSurface, SrcSurfaceSize, pEncryptedBlockInfo, pContentKey, pIV); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This, + IDirect3DSurface9 *pSrcSurface, + UINT *pSurfacePitch ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_GetSurfacePitch(This, pSrcSurface, pSurfacePitch); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This, + void *pRandomNumber, + UINT RandomNumberSize ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_StartSessionKeyRefresh(This, pRandomNumber, RandomNumberSize); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_FinishSessionKeyRefresh(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This, + void *pReadbackKey, + UINT KeySize ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCryptoSession9_GetEncryptionBltKey(This, pReadbackKey, KeySize); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DCryptoSession9Vtbl LockCryptoSession9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockCryptoSession9_GetCertificateSize, + (void *)LockCryptoSession9_GetCertificate, + (void *)LockCryptoSession9_NegotiateKeyExchange, + (void *)LockCryptoSession9_EncryptionBlt, + (void *)LockCryptoSession9_DecryptionBlt, + (void *)LockCryptoSession9_GetSurfacePitch, + (void *)LockCryptoSession9_StartSessionKeyRefresh, + (void *)LockCryptoSession9_FinishSessionKeyRefresh, + (void *)LockCryptoSession9_GetEncryptionBltKey +}; + +#if 0 +static HRESULT WINAPI +LockCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCubeTexture9_GetLevelDesc(This, Level, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT WINAPI +LockCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + IDirect3DSurface9 **ppCubeMapSurface ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCubeTexture9_GetCubeMapSurface(This, FaceType, Level, ppCubeMapSurface); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockCubeTexture9_LockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCubeTexture9_LockRect(This, FaceType, Level, pLockedRect, pRect, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCubeTexture9_UnlockRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + UINT Level ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCubeTexture9_UnlockRect(This, FaceType, Level); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, + D3DCUBEMAP_FACES FaceType, + const RECT *pDirtyRect ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineCubeTexture9_AddDirtyRect(This, FaceType, pDirtyRect); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DCubeTexture9Vtbl LockCubeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)LockBaseTexture9_PreLoad, + (void *)NineResource9_GetType, /* immutable */ + (void *)LockBaseTexture9_SetLOD, + (void *)LockBaseTexture9_GetLOD, + (void *)LockBaseTexture9_GetLevelCount, + (void *)LockBaseTexture9_SetAutoGenFilterType, + (void *)LockBaseTexture9_GetAutoGenFilterType, + (void *)LockBaseTexture9_GenerateMipSubLevels, + (void *)NineCubeTexture9_GetLevelDesc, /* immutable */ + (void *)NineCubeTexture9_GetCubeMapSurface, /* AddRef */ + (void *)LockCubeTexture9_LockRect, + (void *)LockCubeTexture9_UnlockRect, + (void *)LockCubeTexture9_AddDirtyRect +}; + +static HRESULT WINAPI +LockDevice9_TestCooperativeLevel( struct NineDevice9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_TestCooperativeLevel(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static UINT WINAPI +LockDevice9_GetAvailableTextureMem( struct NineDevice9 *This ) +{ + UINT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetAvailableTextureMem(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_EvictManagedResources( struct NineDevice9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_EvictManagedResources(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetDirect3D( struct NineDevice9 *This, + IDirect3D9 **ppD3D9 ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetDirect3D(This, ppD3D9); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockDevice9_GetDeviceCaps( struct NineDevice9 *This, + D3DCAPS9 *pCaps ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetDeviceCaps(This, pCaps); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockDevice9_GetDisplayMode( struct NineDevice9 *This, + UINT iSwapChain, + D3DDISPLAYMODE *pMode ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetDisplayMode(This, iSwapChain, pMode); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockDevice9_GetCreationParameters( struct NineDevice9 *This, + D3DDEVICE_CREATION_PARAMETERS *pParameters ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetCreationParameters(This, pParameters); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockDevice9_SetCursorProperties( struct NineDevice9 *This, + UINT XHotSpot, + UINT YHotSpot, + IDirect3DSurface9 *pCursorBitmap ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetCursorProperties(This, XHotSpot, YHotSpot, pCursorBitmap); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static void WINAPI +LockDevice9_SetCursorPosition( struct NineDevice9 *This, + int X, + int Y, + DWORD Flags ) +{ + pipe_mutex_lock(d3dlock_global); + NineDevice9_SetCursorPosition(This, X, Y, Flags); + pipe_mutex_unlock(d3dlock_global); +} + +static BOOL WINAPI +LockDevice9_ShowCursor( struct NineDevice9 *This, + BOOL bShow ) +{ + BOOL r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_ShowCursor(This, bShow); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + IDirect3DSwapChain9 **pSwapChain ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateAdditionalSwapChain(This, pPresentationParameters, pSwapChain); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetSwapChain( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSwapChain9 **pSwapChain ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetSwapChain(This, iSwapChain, pSwapChain); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static UINT WINAPI +LockDevice9_GetNumberOfSwapChains( struct NineDevice9 *This ) +{ + UINT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetNumberOfSwapChains(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_Reset( struct NineDevice9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_Reset(This, pPresentationParameters); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_Present( struct NineDevice9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetBackBuffer( struct NineDevice9 *This, + UINT iSwapChain, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetBackBuffer(This, iSwapChain, iBackBuffer, Type, ppBackBuffer); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetRasterStatus( struct NineDevice9 *This, + UINT iSwapChain, + D3DRASTER_STATUS *pRasterStatus ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetRasterStatus(This, iSwapChain, pRasterStatus); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetDialogBoxMode( struct NineDevice9 *This, + BOOL bEnableDialogs ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetDialogBoxMode(This, bEnableDialogs); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static void WINAPI +LockDevice9_SetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + DWORD Flags, + const D3DGAMMARAMP *pRamp ) +{ + pipe_mutex_lock(d3dlock_global); + NineDevice9_SetGammaRamp(This, iSwapChain, Flags, pRamp); + pipe_mutex_unlock(d3dlock_global); +} + +static void WINAPI +LockDevice9_GetGammaRamp( struct NineDevice9 *This, + UINT iSwapChain, + D3DGAMMARAMP *pRamp ) +{ + pipe_mutex_lock(d3dlock_global); + NineDevice9_GetGammaRamp(This, iSwapChain, pRamp); + pipe_mutex_unlock(d3dlock_global); +} + +static HRESULT WINAPI +LockDevice9_CreateTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DTexture9 **ppTexture, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateTexture(This, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateVolumeTexture( struct NineDevice9 *This, + UINT Width, + UINT Height, + UINT Depth, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DVolumeTexture9 **ppVolumeTexture, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateVolumeTexture(This, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateCubeTexture( struct NineDevice9 *This, + UINT EdgeLength, + UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DCubeTexture9 **ppCubeTexture, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateCubeTexture(This, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateVertexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + DWORD FVF, + D3DPOOL Pool, + IDirect3DVertexBuffer9 **ppVertexBuffer, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateVertexBuffer(This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateIndexBuffer( struct NineDevice9 *This, + UINT Length, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DIndexBuffer9 **ppIndexBuffer, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateIndexBuffer(This, Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateRenderTarget( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateRenderTarget(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateDepthStencilSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateDepthStencilSurface(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_UpdateSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestinationSurface, + const POINT *pDestPoint ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_UpdateSurface(This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_UpdateTexture( struct NineDevice9 *This, + IDirect3DBaseTexture9 *pSourceTexture, + IDirect3DBaseTexture9 *pDestinationTexture ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_UpdateTexture(This, pSourceTexture, pDestinationTexture); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetRenderTargetData( struct NineDevice9 *This, + IDirect3DSurface9 *pRenderTarget, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetRenderTargetData(This, pRenderTarget, pDestSurface); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetFrontBufferData( struct NineDevice9 *This, + UINT iSwapChain, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetFrontBufferData(This, iSwapChain, pDestSurface); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_StretchRect( struct NineDevice9 *This, + IDirect3DSurface9 *pSourceSurface, + const RECT *pSourceRect, + IDirect3DSurface9 *pDestSurface, + const RECT *pDestRect, + D3DTEXTUREFILTERTYPE Filter ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_StretchRect(This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_ColorFill( struct NineDevice9 *This, + IDirect3DSurface9 *pSurface, + const RECT *pRect, + D3DCOLOR color ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_ColorFill(This, pSurface, pRect, color); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateOffscreenPlainSurface(This, Width, Height, Format, Pool, ppSurface, pSharedHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 *pRenderTarget ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetRenderTarget(This, RenderTargetIndex, pRenderTarget); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetRenderTarget( struct NineDevice9 *This, + DWORD RenderTargetIndex, + IDirect3DSurface9 **ppRenderTarget ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetRenderTarget(This, RenderTargetIndex, ppRenderTarget); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 *pNewZStencil ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetDepthStencilSurface(This, pNewZStencil); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetDepthStencilSurface( struct NineDevice9 *This, + IDirect3DSurface9 **ppZStencilSurface ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetDepthStencilSurface(This, ppZStencilSurface); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_BeginScene( struct NineDevice9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_BeginScene(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_EndScene( struct NineDevice9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_EndScene(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_Clear( struct NineDevice9 *This, + DWORD Count, + const D3DRECT *pRects, + DWORD Flags, + D3DCOLOR Color, + float Z, + DWORD Stencil ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_Clear(This, Count, pRects, Flags, Color, Z, Stencil); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetTransform(This, State, pMatrix); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + D3DMATRIX *pMatrix ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetTransform(This, State, pMatrix); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_MultiplyTransform( struct NineDevice9 *This, + D3DTRANSFORMSTATETYPE State, + const D3DMATRIX *pMatrix ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_MultiplyTransform(This, State, pMatrix); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetViewport( struct NineDevice9 *This, + const D3DVIEWPORT9 *pViewport ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetViewport(This, pViewport); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetViewport( struct NineDevice9 *This, + D3DVIEWPORT9 *pViewport ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetViewport(This, pViewport); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetMaterial( struct NineDevice9 *This, + const D3DMATERIAL9 *pMaterial ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetMaterial(This, pMaterial); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetMaterial( struct NineDevice9 *This, + D3DMATERIAL9 *pMaterial ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetMaterial(This, pMaterial); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetLight( struct NineDevice9 *This, + DWORD Index, + const D3DLIGHT9 *pLight ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetLight(This, Index, pLight); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetLight( struct NineDevice9 *This, + DWORD Index, + D3DLIGHT9 *pLight ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetLight(This, Index, pLight); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_LightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL Enable ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_LightEnable(This, Index, Enable); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetLightEnable( struct NineDevice9 *This, + DWORD Index, + BOOL *pEnable ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetLightEnable(This, Index, pEnable); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetClipPlane( struct NineDevice9 *This, + DWORD Index, + const float *pPlane ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetClipPlane(This, Index, pPlane); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetClipPlane( struct NineDevice9 *This, + DWORD Index, + float *pPlane ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetClipPlane(This, Index, pPlane); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD Value ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetRenderState(This, State, Value); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetRenderState( struct NineDevice9 *This, + D3DRENDERSTATETYPE State, + DWORD *pValue ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetRenderState(This, State, pValue); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateStateBlock( struct NineDevice9 *This, + D3DSTATEBLOCKTYPE Type, + IDirect3DStateBlock9 **ppSB ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateStateBlock(This, Type, ppSB); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_BeginStateBlock( struct NineDevice9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_BeginStateBlock(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_EndStateBlock( struct NineDevice9 *This, + IDirect3DStateBlock9 **ppSB ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_EndStateBlock(This, ppSB); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetClipStatus( struct NineDevice9 *This, + const D3DCLIPSTATUS9 *pClipStatus ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetClipStatus(This, pClipStatus); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetClipStatus( struct NineDevice9 *This, + D3DCLIPSTATUS9 *pClipStatus ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetClipStatus(This, pClipStatus); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 **ppTexture ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetTexture(This, Stage, ppTexture); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetTexture( struct NineDevice9 *This, + DWORD Stage, + IDirect3DBaseTexture9 *pTexture ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetTexture(This, Stage, pTexture); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD *pValue ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetTextureStageState(This, Stage, Type, pValue); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetTextureStageState( struct NineDevice9 *This, + DWORD Stage, + D3DTEXTURESTAGESTATETYPE Type, + DWORD Value ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetTextureStageState(This, Stage, Type, Value); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD *pValue ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetSamplerState(This, Sampler, Type, pValue); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetSamplerState( struct NineDevice9 *This, + DWORD Sampler, + D3DSAMPLERSTATETYPE Type, + DWORD Value ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetSamplerState(This, Sampler, Type, Value); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_ValidateDevice( struct NineDevice9 *This, + DWORD *pNumPasses ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_ValidateDevice(This, pNumPasses); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + const PALETTEENTRY *pEntries ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetPaletteEntries(This, PaletteNumber, pEntries); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetPaletteEntries( struct NineDevice9 *This, + UINT PaletteNumber, + PALETTEENTRY *pEntries ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetPaletteEntries(This, PaletteNumber, pEntries); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetCurrentTexturePalette( struct NineDevice9 *This, + UINT PaletteNumber ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetCurrentTexturePalette(This, PaletteNumber); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetCurrentTexturePalette( struct NineDevice9 *This, + UINT *PaletteNumber ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetCurrentTexturePalette(This, PaletteNumber); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetScissorRect( struct NineDevice9 *This, + const RECT *pRect ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetScissorRect(This, pRect); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetScissorRect( struct NineDevice9 *This, + RECT *pRect ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetScissorRect(This, pRect); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This, + BOOL bSoftware ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetSoftwareVertexProcessing(This, bSoftware); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static BOOL WINAPI +LockDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This ) +{ + BOOL r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetSoftwareVertexProcessing(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetNPatchMode( struct NineDevice9 *This, + float nSegments ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetNPatchMode(This, nSegments); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static float WINAPI +LockDevice9_GetNPatchMode( struct NineDevice9 *This ) +{ + float r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetNPatchMode(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT StartVertex, + UINT PrimitiveCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawPrimitive(This, PrimitiveType, StartVertex, PrimitiveCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + INT BaseVertexIndex, + UINT MinVertexIndex, + UINT NumVertices, + UINT startIndex, + UINT primCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawIndexedPrimitive(This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawPrimitiveUP(This, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This, + D3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex, + UINT NumVertices, + UINT PrimitiveCount, + const void *pIndexData, + D3DFORMAT IndexDataFormat, + const void *pVertexStreamZeroData, + UINT VertexStreamZeroStride ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawIndexedPrimitiveUP(This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_ProcessVertices( struct NineDevice9 *This, + UINT SrcStartIndex, + UINT DestIndex, + UINT VertexCount, + IDirect3DVertexBuffer9 *pDestBuffer, + IDirect3DVertexDeclaration9 *pVertexDecl, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_ProcessVertices(This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateVertexDeclaration( struct NineDevice9 *This, + const D3DVERTEXELEMENT9 *pVertexElements, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateVertexDeclaration(This, pVertexElements, ppDecl); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 *pDecl ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetVertexDeclaration(This, pDecl); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetVertexDeclaration( struct NineDevice9 *This, + IDirect3DVertexDeclaration9 **ppDecl ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetVertexDeclaration(This, ppDecl); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetFVF( struct NineDevice9 *This, + DWORD FVF ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetFVF(This, FVF); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetFVF( struct NineDevice9 *This, + DWORD *pFVF ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetFVF(This, pFVF); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateVertexShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DVertexShader9 **ppShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateVertexShader(This, pFunction, ppShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 *pShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetVertexShader(This, pShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetVertexShader( struct NineDevice9 *This, + IDirect3DVertexShader9 **ppShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetVertexShader(This, ppShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetVertexShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetVertexShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetVertexShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetStreamSource(This, StreamNumber, pStreamData, OffsetInBytes, Stride); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetStreamSource( struct NineDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 **ppStreamData, + UINT *pOffsetInBytes, + UINT *pStride ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetStreamSource(This, StreamNumber, ppStreamData, pOffsetInBytes, pStride); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT Setting ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetStreamSourceFreq(This, StreamNumber, Setting); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetStreamSourceFreq( struct NineDevice9 *This, + UINT StreamNumber, + UINT *pSetting ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetStreamSourceFreq(This, StreamNumber, pSetting); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 *pIndexData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetIndices(This, pIndexData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetIndices( struct NineDevice9 *This, + IDirect3DIndexBuffer9 **ppIndexData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetIndices(This, ppIndexData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreatePixelShader( struct NineDevice9 *This, + const DWORD *pFunction, + IDirect3DPixelShader9 **ppShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreatePixelShader(This, pFunction, ppShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 *pShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetPixelShader(This, pShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetPixelShader( struct NineDevice9 *This, + IDirect3DPixelShader9 **ppShader ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetPixelShader(This, ppShader); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + const float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetPixelShaderConstantF( struct NineDevice9 *This, + UINT StartRegister, + float *pConstantData, + UINT Vector4fCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + const int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetPixelShaderConstantI( struct NineDevice9 *This, + UINT StartRegister, + int *pConstantData, + UINT Vector4iCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + const BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_SetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_GetPixelShaderConstantB( struct NineDevice9 *This, + UINT StartRegister, + BOOL *pConstantData, + UINT BoolCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_GetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawRectPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DRECTPATCH_INFO *pRectPatchInfo ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawRectPatch(This, Handle, pNumSegs, pRectPatchInfo); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DrawTriPatch( struct NineDevice9 *This, + UINT Handle, + const float *pNumSegs, + const D3DTRIPATCH_INFO *pTriPatchInfo ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DrawTriPatch(This, Handle, pNumSegs, pTriPatchInfo); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_DeletePatch( struct NineDevice9 *This, + UINT Handle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_DeletePatch(This, Handle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9_CreateQuery( struct NineDevice9 *This, + D3DQUERYTYPE Type, + IDirect3DQuery9 **ppQuery ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9_CreateQuery(This, Type, ppQuery); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DDevice9Vtbl LockDevice9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockDevice9_TestCooperativeLevel, + (void *)LockDevice9_GetAvailableTextureMem, + (void *)LockDevice9_EvictManagedResources, + (void *)LockDevice9_GetDirect3D, + (void *)NineDevice9_GetDeviceCaps, /* immutable */ + (void *)LockDevice9_GetDisplayMode, + (void *)NineDevice9_GetCreationParameters, /* immutable */ + (void *)LockDevice9_SetCursorProperties, + (void *)LockDevice9_SetCursorPosition, + (void *)LockDevice9_ShowCursor, + (void *)LockDevice9_CreateAdditionalSwapChain, + (void *)LockDevice9_GetSwapChain, + (void *)LockDevice9_GetNumberOfSwapChains, + (void *)LockDevice9_Reset, + (void *)LockDevice9_Present, + (void *)LockDevice9_GetBackBuffer, + (void *)LockDevice9_GetRasterStatus, + (void *)LockDevice9_SetDialogBoxMode, + (void *)LockDevice9_SetGammaRamp, + (void *)LockDevice9_GetGammaRamp, + (void *)LockDevice9_CreateTexture, + (void *)LockDevice9_CreateVolumeTexture, + (void *)LockDevice9_CreateCubeTexture, + (void *)LockDevice9_CreateVertexBuffer, + (void *)LockDevice9_CreateIndexBuffer, + (void *)LockDevice9_CreateRenderTarget, + (void *)LockDevice9_CreateDepthStencilSurface, + (void *)LockDevice9_UpdateSurface, + (void *)LockDevice9_UpdateTexture, + (void *)LockDevice9_GetRenderTargetData, + (void *)LockDevice9_GetFrontBufferData, + (void *)LockDevice9_StretchRect, + (void *)LockDevice9_ColorFill, + (void *)LockDevice9_CreateOffscreenPlainSurface, + (void *)LockDevice9_SetRenderTarget, + (void *)LockDevice9_GetRenderTarget, + (void *)LockDevice9_SetDepthStencilSurface, + (void *)LockDevice9_GetDepthStencilSurface, + (void *)LockDevice9_BeginScene, + (void *)LockDevice9_EndScene, + (void *)LockDevice9_Clear, + (void *)LockDevice9_SetTransform, + (void *)LockDevice9_GetTransform, + (void *)LockDevice9_MultiplyTransform, + (void *)LockDevice9_SetViewport, + (void *)LockDevice9_GetViewport, + (void *)LockDevice9_SetMaterial, + (void *)LockDevice9_GetMaterial, + (void *)LockDevice9_SetLight, + (void *)LockDevice9_GetLight, + (void *)LockDevice9_LightEnable, + (void *)LockDevice9_GetLightEnable, + (void *)LockDevice9_SetClipPlane, + (void *)LockDevice9_GetClipPlane, + (void *)LockDevice9_SetRenderState, + (void *)LockDevice9_GetRenderState, + (void *)LockDevice9_CreateStateBlock, + (void *)LockDevice9_BeginStateBlock, + (void *)LockDevice9_EndStateBlock, + (void *)LockDevice9_SetClipStatus, + (void *)LockDevice9_GetClipStatus, + (void *)LockDevice9_GetTexture, + (void *)LockDevice9_SetTexture, + (void *)LockDevice9_GetTextureStageState, + (void *)LockDevice9_SetTextureStageState, + (void *)LockDevice9_GetSamplerState, + (void *)LockDevice9_SetSamplerState, + (void *)LockDevice9_ValidateDevice, + (void *)LockDevice9_SetPaletteEntries, + (void *)LockDevice9_GetPaletteEntries, + (void *)LockDevice9_SetCurrentTexturePalette, + (void *)LockDevice9_GetCurrentTexturePalette, + (void *)LockDevice9_SetScissorRect, + (void *)LockDevice9_GetScissorRect, + (void *)LockDevice9_SetSoftwareVertexProcessing, + (void *)LockDevice9_GetSoftwareVertexProcessing, + (void *)LockDevice9_SetNPatchMode, + (void *)LockDevice9_GetNPatchMode, + (void *)LockDevice9_DrawPrimitive, + (void *)LockDevice9_DrawIndexedPrimitive, + (void *)LockDevice9_DrawPrimitiveUP, + (void *)LockDevice9_DrawIndexedPrimitiveUP, + (void *)LockDevice9_ProcessVertices, + (void *)LockDevice9_CreateVertexDeclaration, + (void *)LockDevice9_SetVertexDeclaration, + (void *)LockDevice9_GetVertexDeclaration, + (void *)LockDevice9_SetFVF, + (void *)LockDevice9_GetFVF, + (void *)LockDevice9_CreateVertexShader, + (void *)LockDevice9_SetVertexShader, + (void *)LockDevice9_GetVertexShader, + (void *)LockDevice9_SetVertexShaderConstantF, + (void *)LockDevice9_GetVertexShaderConstantF, + (void *)LockDevice9_SetVertexShaderConstantI, + (void *)LockDevice9_GetVertexShaderConstantI, + (void *)LockDevice9_SetVertexShaderConstantB, + (void *)LockDevice9_GetVertexShaderConstantB, + (void *)LockDevice9_SetStreamSource, + (void *)LockDevice9_GetStreamSource, + (void *)LockDevice9_SetStreamSourceFreq, + (void *)LockDevice9_GetStreamSourceFreq, + (void *)LockDevice9_SetIndices, + (void *)LockDevice9_GetIndices, + (void *)LockDevice9_CreatePixelShader, + (void *)LockDevice9_SetPixelShader, + (void *)LockDevice9_GetPixelShader, + (void *)LockDevice9_SetPixelShaderConstantF, + (void *)LockDevice9_GetPixelShaderConstantF, + (void *)LockDevice9_SetPixelShaderConstantI, + (void *)LockDevice9_GetPixelShaderConstantI, + (void *)LockDevice9_SetPixelShaderConstantB, + (void *)LockDevice9_GetPixelShaderConstantB, + (void *)LockDevice9_DrawRectPatch, + (void *)LockDevice9_DrawTriPatch, + (void *)LockDevice9_DeletePatch, + (void *)LockDevice9_CreateQuery +}; + +static HRESULT WINAPI +LockDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This, + UINT width, + UINT height, + float *rows, + float *columns ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_SetConvolutionMonoKernel(This, width, height, rows, columns); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_ComposeRects( struct NineDevice9Ex *This, + IDirect3DSurface9 *pSrc, + IDirect3DSurface9 *pDst, + IDirect3DVertexBuffer9 *pSrcRectDescs, + UINT NumRects, + IDirect3DVertexBuffer9 *pDstRectDescs, + D3DCOMPOSERECTSOP Operation, + int Xoffset, + int Yoffset ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_ComposeRects(This, pSrc, pDst, pSrcRectDescs, NumRects, pDstRectDescs, Operation, Xoffset, Yoffset); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_PresentEx( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_PresentEx(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, + INT *pPriority ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_GetGPUThreadPriority(This, pPriority); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This, + INT Priority ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_SetGPUThreadPriority(This, Priority); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This, + UINT iSwapChain ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_WaitForVBlank(This, iSwapChain); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This, + IDirect3DResource9 **pResourceArray, + UINT32 NumResources ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_CheckResourceResidency(This, pResourceArray, NumResources); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT MaxLatency ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_SetMaximumFrameLatency(This, MaxLatency); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This, + UINT *pMaxLatency ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_GetMaximumFrameLatency(This, pMaxLatency); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, + HWND hDestinationWindow ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_CheckDeviceState(This, hDestinationWindow); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_CreateRenderTargetEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle, Usage); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DPOOL Pool, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_CreateOffscreenPlainSurfaceEx(This, Width, Height, Format, Pool, ppSurface, pSharedHandle, Usage); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This, + UINT Width, + UINT Height, + D3DFORMAT Format, + D3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, + IDirect3DSurface9 **ppSurface, + HANDLE *pSharedHandle, + DWORD Usage ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_CreateDepthStencilSurfaceEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle, Usage); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_ResetEx( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters, + D3DDISPLAYMODEEX *pFullscreenDisplayMode ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_ResetEx(This, pPresentationParameters, pFullscreenDisplayMode); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, + UINT iSwapChain, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Ex_GetDisplayModeEx(This, iSwapChain, pMode, pRotation); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DDevice9ExVtbl LockDevice9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockDevice9_TestCooperativeLevel, + (void *)LockDevice9_GetAvailableTextureMem, + (void *)LockDevice9_EvictManagedResources, + (void *)LockDevice9_GetDirect3D, + (void *)NineDevice9_GetDeviceCaps, + (void *)LockDevice9_GetDisplayMode, + (void *)NineDevice9_GetCreationParameters, + (void *)LockDevice9_SetCursorProperties, + (void *)LockDevice9_SetCursorPosition, + (void *)LockDevice9_ShowCursor, + (void *)LockDevice9_CreateAdditionalSwapChain, + (void *)LockDevice9_GetSwapChain, + (void *)LockDevice9_GetNumberOfSwapChains, + (void *)LockDevice9_Reset, + (void *)LockDevice9_Present, + (void *)LockDevice9_GetBackBuffer, + (void *)LockDevice9_GetRasterStatus, + (void *)LockDevice9_SetDialogBoxMode, + (void *)LockDevice9_SetGammaRamp, + (void *)LockDevice9_GetGammaRamp, + (void *)LockDevice9_CreateTexture, + (void *)LockDevice9_CreateVolumeTexture, + (void *)LockDevice9_CreateCubeTexture, + (void *)LockDevice9_CreateVertexBuffer, + (void *)LockDevice9_CreateIndexBuffer, + (void *)LockDevice9_CreateRenderTarget, + (void *)LockDevice9_CreateDepthStencilSurface, + (void *)LockDevice9_UpdateSurface, + (void *)LockDevice9_UpdateTexture, + (void *)LockDevice9_GetRenderTargetData, + (void *)LockDevice9_GetFrontBufferData, + (void *)LockDevice9_StretchRect, + (void *)LockDevice9_ColorFill, + (void *)LockDevice9_CreateOffscreenPlainSurface, + (void *)LockDevice9_SetRenderTarget, + (void *)LockDevice9_GetRenderTarget, + (void *)LockDevice9_SetDepthStencilSurface, + (void *)LockDevice9_GetDepthStencilSurface, + (void *)LockDevice9_BeginScene, + (void *)LockDevice9_EndScene, + (void *)LockDevice9_Clear, + (void *)LockDevice9_SetTransform, + (void *)LockDevice9_GetTransform, + (void *)LockDevice9_MultiplyTransform, + (void *)LockDevice9_SetViewport, + (void *)LockDevice9_GetViewport, + (void *)LockDevice9_SetMaterial, + (void *)LockDevice9_GetMaterial, + (void *)LockDevice9_SetLight, + (void *)LockDevice9_GetLight, + (void *)LockDevice9_LightEnable, + (void *)LockDevice9_GetLightEnable, + (void *)LockDevice9_SetClipPlane, + (void *)LockDevice9_GetClipPlane, + (void *)LockDevice9_SetRenderState, + (void *)LockDevice9_GetRenderState, + (void *)LockDevice9_CreateStateBlock, + (void *)LockDevice9_BeginStateBlock, + (void *)LockDevice9_EndStateBlock, + (void *)LockDevice9_SetClipStatus, + (void *)LockDevice9_GetClipStatus, + (void *)LockDevice9_GetTexture, + (void *)LockDevice9_SetTexture, + (void *)LockDevice9_GetTextureStageState, + (void *)LockDevice9_SetTextureStageState, + (void *)LockDevice9_GetSamplerState, + (void *)LockDevice9_SetSamplerState, + (void *)LockDevice9_ValidateDevice, + (void *)LockDevice9_SetPaletteEntries, + (void *)LockDevice9_GetPaletteEntries, + (void *)LockDevice9_SetCurrentTexturePalette, + (void *)LockDevice9_GetCurrentTexturePalette, + (void *)LockDevice9_SetScissorRect, + (void *)LockDevice9_GetScissorRect, + (void *)LockDevice9_SetSoftwareVertexProcessing, + (void *)LockDevice9_GetSoftwareVertexProcessing, + (void *)LockDevice9_SetNPatchMode, + (void *)LockDevice9_GetNPatchMode, + (void *)LockDevice9_DrawPrimitive, + (void *)LockDevice9_DrawIndexedPrimitive, + (void *)LockDevice9_DrawPrimitiveUP, + (void *)LockDevice9_DrawIndexedPrimitiveUP, + (void *)LockDevice9_ProcessVertices, + (void *)LockDevice9_CreateVertexDeclaration, + (void *)LockDevice9_SetVertexDeclaration, + (void *)LockDevice9_GetVertexDeclaration, + (void *)LockDevice9_SetFVF, + (void *)LockDevice9_GetFVF, + (void *)LockDevice9_CreateVertexShader, + (void *)LockDevice9_SetVertexShader, + (void *)LockDevice9_GetVertexShader, + (void *)LockDevice9_SetVertexShaderConstantF, + (void *)LockDevice9_GetVertexShaderConstantF, + (void *)LockDevice9_SetVertexShaderConstantI, + (void *)LockDevice9_GetVertexShaderConstantI, + (void *)LockDevice9_SetVertexShaderConstantB, + (void *)LockDevice9_GetVertexShaderConstantB, + (void *)LockDevice9_SetStreamSource, + (void *)LockDevice9_GetStreamSource, + (void *)LockDevice9_SetStreamSourceFreq, + (void *)LockDevice9_GetStreamSourceFreq, + (void *)LockDevice9_SetIndices, + (void *)LockDevice9_GetIndices, + (void *)LockDevice9_CreatePixelShader, + (void *)LockDevice9_SetPixelShader, + (void *)LockDevice9_GetPixelShader, + (void *)LockDevice9_SetPixelShaderConstantF, + (void *)LockDevice9_GetPixelShaderConstantF, + (void *)LockDevice9_SetPixelShaderConstantI, + (void *)LockDevice9_GetPixelShaderConstantI, + (void *)LockDevice9_SetPixelShaderConstantB, + (void *)LockDevice9_GetPixelShaderConstantB, + (void *)LockDevice9_DrawRectPatch, + (void *)LockDevice9_DrawTriPatch, + (void *)LockDevice9_DeletePatch, + (void *)LockDevice9_CreateQuery, + (void *)LockDevice9Ex_SetConvolutionMonoKernel, + (void *)LockDevice9Ex_ComposeRects, + (void *)LockDevice9Ex_PresentEx, + (void *)LockDevice9Ex_GetGPUThreadPriority, + (void *)LockDevice9Ex_SetGPUThreadPriority, + (void *)LockDevice9Ex_WaitForVBlank, + (void *)LockDevice9Ex_CheckResourceResidency, + (void *)LockDevice9Ex_SetMaximumFrameLatency, + (void *)LockDevice9Ex_GetMaximumFrameLatency, + (void *)LockDevice9Ex_CheckDeviceState, + (void *)LockDevice9Ex_CreateRenderTargetEx, + (void *)LockDevice9Ex_CreateOffscreenPlainSurfaceEx, + (void *)LockDevice9Ex_CreateDepthStencilSurfaceEx, + (void *)LockDevice9Ex_ResetEx, + (void *)LockDevice9Ex_GetDisplayModeEx +}; + +static HRESULT WINAPI +LockDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + D3DCONTENTPROTECTIONCAPS *pCaps ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Video_GetContentProtectionCaps(This, pCryptoType, pDecodeProfile, pCaps); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This, + D3DAUTHENTICATEDCHANNELTYPE ChannelType, + IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, + HANDLE *pChannelHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Video_CreateAuthenticatedChannel(This, ChannelType, ppAuthenticatedChannel, pChannelHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockDevice9Video_CreateCryptoSession( struct NineDevice9Video *This, + const GUID *pCryptoType, + const GUID *pDecodeProfile, + IDirect3DCryptoSession9 **ppCryptoSession, + HANDLE *pCryptoHandle ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineDevice9Video_CreateCryptoSession(This, pCryptoType, pDecodeProfile, ppCryptoSession, pCryptoHandle); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DDevice9VideoVtbl LockDevice9Video_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockDevice9Video_GetContentProtectionCaps, + (void *)LockDevice9Video_CreateAuthenticatedChannel, + (void *)LockDevice9Video_CreateCryptoSession +}; + +static HRESULT WINAPI +LockIndexBuffer9_Lock( struct NineIndexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineIndexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockIndexBuffer9_Unlock( struct NineIndexBuffer9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineIndexBuffer9_Unlock(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This, + D3DINDEXBUFFER_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineIndexBuffer9_GetDesc(This, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +IDirect3DIndexBuffer9Vtbl LockIndexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)NineResource9_PreLoad, /* nop */ + (void *)NineResource9_GetType, /* immutable */ + (void *)LockIndexBuffer9_Lock, + (void *)LockIndexBuffer9_Unlock, + (void *)NineIndexBuffer9_GetDesc /* immutable */ +}; + +#if 0 +static HRESULT WINAPI +LockPixelShader9_GetDevice( struct NinePixelShader9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockPixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NinePixelShader9_GetFunction(This, pData, pSizeOfData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DPixelShader9Vtbl LockPixelShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, + (void *)LockPixelShader9_GetFunction +}; + +#if 0 +static HRESULT WINAPI +LockQuery9_GetDevice( struct NineQuery9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +#if 0 +static D3DQUERYTYPE WINAPI +LockQuery9_GetType( struct NineQuery9 *This ) +{ + D3DQUERYTYPE r; + pipe_mutex_lock(d3dlock_global); + r = NineQuery9_GetType(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +#if 0 +static DWORD WINAPI +LockQuery9_GetDataSize( struct NineQuery9 *This ) +{ + DWORD r; + pipe_mutex_lock(d3dlock_global); + r = NineQuery9_GetDataSize(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineQuery9_Issue(This, dwIssueFlags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineQuery9_GetData(This, pData, dwSize, dwGetDataFlags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DQuery9Vtbl LockQuery9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */ + (void *)NineQuery9_GetType, /* immutable */ + (void *)NineQuery9_GetDataSize, /* immutable */ + (void *)LockQuery9_Issue, + (void *)LockQuery9_GetData +}; + +#if 0 +static HRESULT WINAPI +LockStateBlock9_GetDevice( struct NineStateBlock9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockStateBlock9_Capture( struct NineStateBlock9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineStateBlock9_Capture(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockStateBlock9_Apply( struct NineStateBlock9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineStateBlock9_Apply(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DStateBlock9Vtbl LockStateBlock9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */ + (void *)LockStateBlock9_Capture, + (void *)LockStateBlock9_Apply +}; + +static HRESULT WINAPI +LockSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_GetContainer(This, riid, ppContainer); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_GetDesc(This, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_LockRect(This, pLockedRect, pRect, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSurface9_UnlockRect( struct NineSurface9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_UnlockRect(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_GetDC(This, phdc); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSurface9_ReleaseDC(This, hdc); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DSurface9Vtbl LockSurface9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)NineResource9_PreLoad, /* nop */ + (void *)NineResource9_GetType, /* immutable */ + (void *)LockSurface9_GetContainer, + (void *)NineSurface9_GetDesc, /* immutable */ + (void *)LockSurface9_LockRect, + (void *)LockSurface9_UnlockRect, + (void *)LockSurface9_GetDC, + (void *)LockSurface9_ReleaseDC +}; + +static HRESULT WINAPI +LockSwapChain9_Present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, + IDirect3DSurface9 *pDestSurface ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_GetFrontBufferData(This, pDestSurface); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_GetBackBuffer(This, iBackBuffer, Type, ppBackBuffer); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, + D3DRASTER_STATUS *pRasterStatus ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_GetRasterStatus(This, pRasterStatus); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, + D3DDISPLAYMODE *pMode ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_GetDisplayMode(This, pMode); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockSwapChain9_GetDevice( struct NineSwapChain9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9_GetPresentParameters(This, pPresentationParameters); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DSwapChain9Vtbl LockSwapChain9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockSwapChain9_Present, + (void *)LockSwapChain9_GetFrontBufferData, + (void *)LockSwapChain9_GetBackBuffer, + (void *)LockSwapChain9_GetRasterStatus, + (void *)LockSwapChain9_GetDisplayMode, + (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */ + (void *)LockSwapChain9_GetPresentParameters +}; + +static HRESULT WINAPI +LockSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9Ex_GetLastPresentCount(This, pLastPresentCount); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9Ex_GetPresentStats(This, pPresentationStatistics); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineSwapChain9Ex_GetDisplayModeEx(This, pMode, pRotation); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DSwapChain9ExVtbl LockSwapChain9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)LockSwapChain9_Present, + (void *)LockSwapChain9_GetFrontBufferData, + (void *)LockSwapChain9_GetBackBuffer, + (void *)LockSwapChain9_GetRasterStatus, + (void *)LockSwapChain9_GetDisplayMode, + (void *)NineUnknown_GetDevice, /* actually part of NineSwapChain9 iface */ + (void *)LockSwapChain9_GetPresentParameters, + (void *)LockSwapChain9Ex_GetLastPresentCount, + (void *)LockSwapChain9Ex_GetPresentStats, + (void *)LockSwapChain9Ex_GetDisplayModeEx +}; + +#if 0 +static HRESULT WINAPI +LockTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineTexture9_GetLevelDesc(This, Level, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT WINAPI +LockTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineTexture9_GetSurfaceLevel(This, Level, ppSurfaceLevel); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineTexture9_LockRect(This, Level, pLockedRect, pRect, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineTexture9_UnlockRect(This, Level); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockTexture9_AddDirtyRect( struct NineTexture9 *This, + const RECT *pDirtyRect ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineTexture9_AddDirtyRect(This, pDirtyRect); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DTexture9Vtbl LockTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)LockBaseTexture9_PreLoad, + (void *)NineResource9_GetType, /* immutable */ + (void *)LockBaseTexture9_SetLOD, + (void *)LockBaseTexture9_GetLOD, + (void *)LockBaseTexture9_GetLevelCount, + (void *)LockBaseTexture9_SetAutoGenFilterType, + (void *)LockBaseTexture9_GetAutoGenFilterType, + (void *)LockBaseTexture9_GenerateMipSubLevels, + (void *)NineTexture9_GetLevelDesc, /* immutable */ + (void *)NineTexture9_GetSurfaceLevel, /* AddRef */ + (void *)LockTexture9_LockRect, + (void *)LockTexture9_UnlockRect, + (void *)LockTexture9_AddDirtyRect +}; + +static HRESULT WINAPI +LockVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVertexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVertexBuffer9_Unlock(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This, + D3DVERTEXBUFFER_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVertexBuffer9_GetDesc(This, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +IDirect3DVertexBuffer9Vtbl LockVertexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)NineResource9_PreLoad, /* nop */ + (void *)NineResource9_GetType, /* immutable */ + (void *)LockVertexBuffer9_Lock, + (void *)LockVertexBuffer9_Unlock, + (void *)NineVertexBuffer9_GetDesc /* immutable */ +}; + +#if 0 +static HRESULT WINAPI +LockVertexDeclaration9_GetDevice( struct NineVertexDeclaration9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, + D3DVERTEXELEMENT9 *pElement, + UINT *pNumElements ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVertexDeclaration9_GetDeclaration(This, pElement, pNumElements); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DVertexDeclaration9Vtbl LockVertexDeclaration9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */ + (void *)LockVertexDeclaration9_GetDeclaration +}; + +#if 0 +static HRESULT WINAPI +LockVertexShader9_GetDevice( struct NineVertexShader9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockVertexShader9_GetFunction( struct NineVertexShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVertexShader9_GetFunction(This, pData, pSizeOfData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DVertexShader9Vtbl LockVertexShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, + (void *)LockVertexShader9_GetFunction +}; + +#if 0 +static HRESULT WINAPI +LockVolume9_GetDevice( struct NineVolume9 *This, + IDirect3DDevice9 **ppDevice ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineUnknown_GetDevice(NineUnknown(This), ppDevice); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockVolume9_SetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_SetPrivateData(This, refguid, pData, SizeOfData, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolume9_GetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_GetPrivateData(This, refguid, pData, pSizeOfData); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolume9_FreePrivateData( struct NineVolume9 *This, + REFGUID refguid ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_FreePrivateData(This, refguid); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_GetContainer(This, riid, ppContainer); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +#if 0 +static HRESULT WINAPI +LockVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_GetDesc(This, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_LockBox(This, pLockedVolume, pBox, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolume9_UnlockBox( struct NineVolume9 *This ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolume9_UnlockBox(This); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DVolume9Vtbl LockVolume9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */ + (void *)LockVolume9_SetPrivateData, + (void *)LockVolume9_GetPrivateData, + (void *)LockVolume9_FreePrivateData, + (void *)LockVolume9_GetContainer, + (void *)NineVolume9_GetDesc, /* immutable */ + (void *)LockVolume9_LockBox, + (void *)LockVolume9_UnlockBox +}; + +#if 0 +static HRESULT WINAPI +LockVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolumeTexture9_GetLevelDesc(This, Level, pDesc); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +#if 0 +static HRESULT WINAPI +LockVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolumeTexture9_GetVolumeLevel(This, Level, ppVolumeLevel); + pipe_mutex_unlock(d3dlock_global); + return r; +} +#endif + +static HRESULT WINAPI +LockVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolumeTexture9_LockBox(This, Level, pLockedVolume, pBox, Flags); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolumeTexture9_UnlockBox(This, Level); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +static HRESULT WINAPI +LockVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ) +{ + HRESULT r; + pipe_mutex_lock(d3dlock_global); + r = NineVolumeTexture9_AddDirtyBox(This, pDirtyBox); + pipe_mutex_unlock(d3dlock_global); + return r; +} + +IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)LockResource9_SetPrivateData, + (void *)LockResource9_GetPrivateData, + (void *)LockResource9_FreePrivateData, + (void *)LockResource9_SetPriority, + (void *)LockResource9_GetPriority, + (void *)LockBaseTexture9_PreLoad, + (void *)NineResource9_GetType, /* immutable */ + (void *)LockBaseTexture9_SetLOD, + (void *)LockBaseTexture9_GetLOD, + (void *)LockBaseTexture9_GetLevelCount, + (void *)LockBaseTexture9_SetAutoGenFilterType, + (void *)LockBaseTexture9_GetAutoGenFilterType, + (void *)LockBaseTexture9_GenerateMipSubLevels, + (void *)NineVolumeTexture9_GetLevelDesc, /* immutable */ + (void *)NineVolumeTexture9_GetVolumeLevel, /* AddRef */ + (void *)LockVolumeTexture9_LockBox, + (void *)LockVolumeTexture9_UnlockBox, + (void *)LockVolumeTexture9_AddDirtyBox +}; + +ID3DAdapter9Vtbl LockAdapter9_vtable = { /* not used */ + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL +}; diff --git a/src/gallium/state_trackers/nine/nine_lock.h b/src/gallium/state_trackers/nine/nine_lock.h new file mode 100644 index 00000000000..9738a203c14 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_lock.h @@ -0,0 +1,51 @@ +/* + * Copyright 2013 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_LOCK_H_ +#define _NINE_LOCK_H_ + +#include "d3d9.h" +#include "d3dadapter/d3dadapter9.h" + +extern IDirect3DAuthenticatedChannel9Vtbl LockAuthenticatedChannel9_vtable; +extern IDirect3DCryptoSession9Vtbl LockCryptoSession9_vtable; +extern IDirect3DCubeTexture9Vtbl LockCubeTexture9_vtable; +extern IDirect3DDevice9Vtbl LockDevice9_vtable; +extern IDirect3DDevice9ExVtbl LockDevice9Ex_vtable; +extern IDirect3DDevice9VideoVtbl LockDevice9Video_vtable; +extern IDirect3DIndexBuffer9Vtbl LockIndexBuffer9_vtable; +extern IDirect3DPixelShader9Vtbl LockPixelShader9_vtable; +extern IDirect3DQuery9Vtbl LockQuery9_vtable; +extern IDirect3DStateBlock9Vtbl LockStateBlock9_vtable; +extern IDirect3DSurface9Vtbl LockSurface9_vtable; +extern IDirect3DSwapChain9Vtbl LockSwapChain9_vtable; +extern IDirect3DSwapChain9ExVtbl LockSwapChain9Ex_vtable; +extern IDirect3DTexture9Vtbl LockTexture9_vtable; +extern IDirect3DVertexBuffer9Vtbl LockVertexBuffer9_vtable; +extern IDirect3DVertexDeclaration9Vtbl LockVertexDeclaration9_vtable; +extern IDirect3DVertexShader9Vtbl LockVertexShader9_vtable; +extern IDirect3DVolume9Vtbl LockVolume9_vtable; +extern IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable; +extern IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable; +extern ID3DAdapter9Vtbl LockAdapter9_vtable; + +#endif /* _NINE_LOCK_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_pdata.h b/src/gallium/state_trackers/nine/nine_pdata.h new file mode 100644 index 00000000000..7bdd702cfbb --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_pdata.h @@ -0,0 +1,45 @@ + +#ifndef _NINE_PDATA_H_ +#define _NINE_PDATA_H_ + +struct pheader +{ + boolean unknown; + DWORD size; + char data[1]; +}; + +static int +ht_guid_compare( void *a, + void *b ) +{ + return GUID_equal(a, b) ? 0 : 1; +} + +static unsigned +ht_guid_hash( void *key ) +{ + unsigned i, hash = 0; + const unsigned char *str = key; + + for (i = 0; i < sizeof(GUID); i++) { + hash = (unsigned)(str[i]) + (hash << 6) + (hash << 16) - hash; + } + + return hash; +} + +static enum pipe_error +ht_guid_delete( void *key, + void *value, + void *data ) +{ + struct pheader *header = value; + + if (header->unknown) { IUnknown_Release(*(IUnknown **)header->data); } + FREE(header); + + return PIPE_OK; +} + +#endif /* _NINE_PDATA_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_pipe.c b/src/gallium/state_trackers/nine/nine_pipe.c new file mode 100644 index 00000000000..3a7bb90d222 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_pipe.c @@ -0,0 +1,410 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * Copyright 2013 Christoph Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "nine_pipe.h" + +#include "cso_cache/cso_context.h" + +void +nine_convert_dsa_state(struct cso_context *ctx, const DWORD *rs) +{ + struct pipe_depth_stencil_alpha_state dsa; + + memset(&dsa, 0, sizeof(dsa)); /* memcmp safety */ + + if (rs[D3DRS_ZENABLE]) { + dsa.depth.enabled = 1; + dsa.depth.writemask = !!rs[D3DRS_ZWRITEENABLE]; + dsa.depth.func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ZFUNC]); + } + + if (rs[D3DRS_STENCILENABLE]) { + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = d3dcmpfunc_to_pipe_func(rs[D3DRS_STENCILFUNC]); + dsa.stencil[0].fail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILFAIL]); + dsa.stencil[0].zpass_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILPASS]); + dsa.stencil[0].zfail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILZFAIL]); + dsa.stencil[0].valuemask = rs[D3DRS_STENCILMASK]; + dsa.stencil[0].writemask = rs[D3DRS_STENCILWRITEMASK]; + + if (rs[D3DRS_TWOSIDEDSTENCILMODE]) { + dsa.stencil[1].enabled = 1; + dsa.stencil[1].func = d3dcmpfunc_to_pipe_func(rs[D3DRS_CCW_STENCILFUNC]); + dsa.stencil[1].fail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILFAIL]); + dsa.stencil[1].zpass_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILPASS]); + dsa.stencil[1].zfail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILZFAIL]); + dsa.stencil[1].valuemask = dsa.stencil[0].valuemask; + dsa.stencil[1].writemask = dsa.stencil[0].writemask; + } + } + + if (rs[D3DRS_ALPHATESTENABLE]) { + dsa.alpha.enabled = 1; + dsa.alpha.func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ALPHAFUNC]); + dsa.alpha.ref_value = (float)rs[D3DRS_ALPHAREF] / 255.0f; + } + + cso_set_depth_stencil_alpha(ctx, &dsa); +} + +/* TODO: Keep a static copy in device so we don't have to memset every time ? */ +void +nine_convert_rasterizer_state(struct cso_context *ctx, const DWORD *rs) +{ + struct pipe_rasterizer_state rast; + + memset(&rast, 0, sizeof(rast)); /* memcmp safety */ + + rast.flatshade = rs[D3DRS_SHADEMODE] == D3DSHADE_FLAT; + /* rast.light_twoside = 0; */ + /* rast.clamp_fragment_color = 0; */ + /* rast.clamp_vertex_color = 0; */ + /* rast.front_ccw = 0; */ + rast.cull_face = d3dcull_to_pipe_face(rs[D3DRS_CULLMODE]); + rast.fill_front = d3dfillmode_to_pipe_polygon_mode(rs[D3DRS_FILLMODE]); + rast.fill_back = rast.fill_front; + rast.offset_tri = !!(rs[D3DRS_DEPTHBIAS] | rs[D3DRS_SLOPESCALEDEPTHBIAS]); + rast.offset_line = rast.offset_tri; /* triangles in wireframe mode */ + rast.offset_point = 0; /* XXX ? */ + rast.scissor = !!rs[D3DRS_SCISSORTESTENABLE]; + /* rast.poly_smooth = 0; */ + /* rast.poly_stipple_enable = 0; */ + /* rast.point_smooth = 0; */ + rast.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; + rast.point_quad_rasterization = !!rs[D3DRS_POINTSPRITEENABLE]; + rast.point_size_per_vertex = rs[NINED3DRS_VSPOINTSIZE]; + rast.multisample = !!rs[D3DRS_MULTISAMPLEANTIALIAS]; + rast.line_smooth = !!rs[D3DRS_ANTIALIASEDLINEENABLE]; + /* rast.line_stipple_enable = 0; */ + rast.line_last_pixel = !!rs[D3DRS_LASTPIXEL]; + rast.flatshade_first = 1; + /* rast.half_pixel_center = 0; */ + /* rast.lower_left_origin = 0; */ + /* rast.bottom_edge_rule = 0; */ + /* rast.rasterizer_discard = 0; */ + rast.depth_clip = 1; + rast.clip_halfz = 1; + rast.clip_plane_enable = rs[D3DRS_CLIPPLANEENABLE]; + /* rast.line_stipple_factor = 0; */ + /* rast.line_stipple_pattern = 0; */ + rast.sprite_coord_enable = rs[D3DRS_POINTSPRITEENABLE] ? 0xff : 0x00; + rast.line_width = 1.0f; + rast.point_size = rs[NINED3DRS_VSPOINTSIZE] ? 1.0f : asfloat(rs[D3DRS_POINTSIZE]); /* XXX: D3DRS_POINTSIZE_MIN/MAX */ + rast.offset_units = asfloat(rs[D3DRS_DEPTHBIAS]) * asfloat(rs[NINED3DRS_ZBIASSCALE]); + rast.offset_scale = asfloat(rs[D3DRS_SLOPESCALEDEPTHBIAS]); + /* rast.offset_clamp = 0.0f; */ + + cso_set_rasterizer(ctx, &rast); +} + +static INLINE void +nine_convert_blend_state_fixup(struct pipe_blend_state *blend, const DWORD *rs) +{ + if (unlikely(rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHSRCALPHA || + rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHINVSRCALPHA)) { + blend->rt[0].rgb_dst_factor = (rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHSRCALPHA) ? + PIPE_BLENDFACTOR_INV_SRC_ALPHA : PIPE_BLENDFACTOR_SRC_ALPHA; + if (!rs[D3DRS_SEPARATEALPHABLENDENABLE]) + blend->rt[0].alpha_dst_factor = blend->rt[0].rgb_dst_factor; + } else + if (unlikely(rs[D3DRS_SEPARATEALPHABLENDENABLE] && + (rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHSRCALPHA || + rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHINVSRCALPHA))) { + blend->rt[0].alpha_dst_factor = (rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHSRCALPHA) ? + PIPE_BLENDFACTOR_INV_SRC_ALPHA : PIPE_BLENDFACTOR_SRC_ALPHA; + } +} + +void +nine_convert_blend_state(struct cso_context *ctx, const DWORD *rs) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(blend)); /* memcmp safety */ + + blend.dither = !!rs[D3DRS_DITHERENABLE]; + + /* blend.alpha_to_one = 0; */ + /* blend.alpha_to_coverage = 0; */ /* XXX */ + + blend.rt[0].blend_enable = !!rs[D3DRS_ALPHABLENDENABLE]; + if (blend.rt[0].blend_enable) { + blend.rt[0].rgb_func = d3dblendop_to_pipe_blend(rs[D3DRS_BLENDOP]); + blend.rt[0].rgb_src_factor = d3dblend_color_to_pipe_blendfactor(rs[D3DRS_SRCBLEND]); + blend.rt[0].rgb_dst_factor = d3dblend_color_to_pipe_blendfactor(rs[D3DRS_DESTBLEND]); + if (rs[D3DRS_SEPARATEALPHABLENDENABLE]) { + blend.rt[0].alpha_func = d3dblendop_to_pipe_blend(rs[D3DRS_BLENDOPALPHA]); + blend.rt[0].alpha_src_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_SRCBLENDALPHA]); + blend.rt[0].alpha_dst_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_DESTBLENDALPHA]); + } else { + /* TODO: Just copy the rgb values ? SRC1_x may differ ... */ + blend.rt[0].alpha_func = blend.rt[0].rgb_func; + blend.rt[0].alpha_src_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_SRCBLEND]); + blend.rt[0].alpha_dst_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_DESTBLEND]); + } + nine_convert_blend_state_fixup(&blend, rs); /* for BOTH[INV]SRCALPHA */ + } + blend.rt[0].colormask = rs[D3DRS_COLORWRITEENABLE]; + + if (rs[D3DRS_COLORWRITEENABLE1] != rs[D3DRS_COLORWRITEENABLE] || + rs[D3DRS_COLORWRITEENABLE2] != rs[D3DRS_COLORWRITEENABLE] || + rs[D3DRS_COLORWRITEENABLE3] != rs[D3DRS_COLORWRITEENABLE]) { + unsigned i; + blend.independent_blend_enable = TRUE; + for (i = 1; i < 4; ++i) + blend.rt[i] = blend.rt[0]; + blend.rt[1].colormask = rs[D3DRS_COLORWRITEENABLE1]; + blend.rt[2].colormask = rs[D3DRS_COLORWRITEENABLE2]; + blend.rt[3].colormask = rs[D3DRS_COLORWRITEENABLE3]; + } + + /* blend.force_srgb = !!rs[D3DRS_SRGBWRITEENABLE]; */ + + cso_set_blend(ctx, &blend); +} + +void +nine_convert_sampler_state(struct cso_context *ctx, int idx, const DWORD *ss) +{ + struct pipe_sampler_state samp; + + assert(idx >= 0 && + (idx < NINE_MAX_SAMPLERS_PS || idx >= NINE_SAMPLER_VS(0)) && + (idx < NINE_MAX_SAMPLERS)); + + memset(&samp, 0, sizeof(samp)); /* memcmp safety */ + + if (ss[D3DSAMP_MIPFILTER] != D3DTEXF_NONE) { + samp.lod_bias = asfloat(ss[D3DSAMP_MIPMAPLODBIAS]); + samp.min_lod = ss[NINED3DSAMP_MINLOD]; + samp.min_mip_filter = (ss[D3DSAMP_MIPFILTER] == D3DTEXF_POINT) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + } else { + samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + } + samp.max_lod = 15.0f; + samp.wrap_s = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSU]); + samp.wrap_t = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSV]); + samp.wrap_r = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSW]); + samp.min_img_filter = ss[D3DSAMP_MINFILTER] == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + samp.mag_img_filter = ss[D3DSAMP_MAGFILTER] == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + if (ss[D3DSAMP_MINFILTER] == D3DTEXF_ANISOTROPIC || + ss[D3DSAMP_MAGFILTER] == D3DTEXF_ANISOTROPIC) + samp.max_anisotropy = ss[D3DSAMP_MAXANISOTROPY]; + samp.compare_mode = ss[NINED3DSAMP_SHADOW] ? PIPE_TEX_COMPARE_R_TO_TEXTURE : PIPE_TEX_COMPARE_NONE; + samp.compare_func = PIPE_FUNC_LEQUAL; + samp.normalized_coords = 1; + samp.seamless_cube_map = 1; + d3dcolor_to_pipe_color_union(&samp.border_color, ss[D3DSAMP_BORDERCOLOR]); + + /* see nine_state.h */ + if (idx < NINE_MAX_SAMPLERS_PS) + cso_single_sampler(ctx, PIPE_SHADER_FRAGMENT, idx - NINE_SAMPLER_PS(0), &samp); + else + cso_single_sampler(ctx, PIPE_SHADER_VERTEX, idx - NINE_SAMPLER_VS(0), &samp); +} + +void +nine_pipe_context_clear(struct NineDevice9 *This) +{ + struct pipe_context *pipe = This->pipe; + struct cso_context *cso = This->cso; + pipe->bind_vs_state(pipe, NULL); + pipe->bind_fs_state(pipe, NULL); + + /* Don't unbind constant buffers, they're device-private and + * do not change on Reset. + */ + + cso_set_samplers(cso, PIPE_SHADER_VERTEX, 0, NULL); + cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 0, NULL); + + pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 0, NULL); + pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, 0, NULL); + + pipe->set_vertex_buffers(pipe, 0, This->caps.MaxStreams, NULL); + pipe->set_index_buffer(pipe, NULL); +} + +const enum pipe_format nine_d3d9_to_pipe_format_map[120] = +{ + [D3DFMT_UNKNOWN] = PIPE_FORMAT_NONE, + + [D3DFMT_A8R8G8B8] = PIPE_FORMAT_B8G8R8A8_UNORM, + [D3DFMT_X8R8G8B8] = PIPE_FORMAT_B8G8R8X8_UNORM, + [D3DFMT_R5G6B5] = PIPE_FORMAT_B5G6R5_UNORM, + [D3DFMT_X1R5G5B5] = PIPE_FORMAT_B5G5R5X1_UNORM, + [D3DFMT_A1R5G5B5] = PIPE_FORMAT_B5G5R5A1_UNORM, + [D3DFMT_A4R4G4B4] = PIPE_FORMAT_B4G4R4A4_UNORM, + [D3DFMT_A8] = PIPE_FORMAT_A8_UNORM, + [D3DFMT_X4R4G4B4] = PIPE_FORMAT_B4G4R4X4_UNORM, + [D3DFMT_R3G3B2] = PIPE_FORMAT_B2G3R3_UNORM, + [D3DFMT_A2B10G10R10] = PIPE_FORMAT_R10G10B10A2_UNORM, + [D3DFMT_A8B8G8R8] = PIPE_FORMAT_R8G8B8A8_UNORM, + [D3DFMT_X8B8G8R8] = PIPE_FORMAT_R8G8B8X8_UNORM, + [D3DFMT_G16R16] = PIPE_FORMAT_R16G16_UNORM, + [D3DFMT_A2R10G10B10] = PIPE_FORMAT_B10G10R10A2_UNORM, + [D3DFMT_A16B16G16R16] = PIPE_FORMAT_R16G16B16A16_UNORM, + + /* palette texture formats not supported by gallium/hardware, TODO ? */ + [D3DFMT_P8] = PIPE_FORMAT_NONE, + [D3DFMT_A8P8] = PIPE_FORMAT_NONE, + + [D3DFMT_L8] = PIPE_FORMAT_L8_UNORM, + [D3DFMT_A8L8] = PIPE_FORMAT_L8A8_UNORM, + [D3DFMT_A4L4] = PIPE_FORMAT_L4A4_UNORM, + + [D3DFMT_V8U8] = PIPE_FORMAT_R8G8_SNORM, + [D3DFMT_Q8W8V8U8] = PIPE_FORMAT_R8G8B8A8_SNORM, + [D3DFMT_V16U16] = PIPE_FORMAT_R16G16_SNORM, + [D3DFMT_A2W10V10U10] = PIPE_FORMAT_R10SG10SB10SA2U_NORM, + + /* [D3DFMT_UYVY] = PIPE_FORMAT_YUYV, fourcc */ + /* [D3DFMT_YUY2] = PIPE_FORMAT_NONE, fourcc */ + + /* XXX: DXT2, DXT4 */ + /* fourcc + [D3DFMT_DXT1] = PIPE_FORMAT_DXT1_RGBA, + [D3DFMT_DXT2] = PIPE_FORMAT_DXT3_RGBA, + [D3DFMT_DXT3] = PIPE_FORMAT_DXT3_RGBA, + [D3DFMT_DXT4] = PIPE_FORMAT_DXT5_RGBA, + [D3DFMT_DXT5] = PIPE_FORMAT_DXT5_RGBA, + */ + + /* XXX: order ? */ + /* fourcc + [D3DFMT_G8R8_G8B8] = PIPE_FORMAT_G8R8_G8B8_UNORM, + [D3DFMT_R8G8_B8G8] = PIPE_FORMAT_R8G8_B8G8_UNORM, + */ + + [D3DFMT_D16_LOCKABLE] = PIPE_FORMAT_Z16_UNORM, + [D3DFMT_D32] = PIPE_FORMAT_Z32_UNORM, + [D3DFMT_D24S8] = PIPE_FORMAT_S8_UINT_Z24_UNORM, + [D3DFMT_D24X8] = PIPE_FORMAT_X8Z24_UNORM, + [D3DFMT_D16] = PIPE_FORMAT_Z16_UNORM, + [D3DFMT_L16] = PIPE_FORMAT_L16_UNORM, + [D3DFMT_D32F_LOCKABLE] = PIPE_FORMAT_Z32_FLOAT, + + [D3DFMT_INDEX16] = PIPE_FORMAT_R16_UINT, + [D3DFMT_INDEX32] = PIPE_FORMAT_R32_UINT, + [D3DFMT_Q16W16V16U16] = PIPE_FORMAT_R16G16B16A16_SNORM, + + [D3DFMT_R16F] = PIPE_FORMAT_R16_FLOAT, + [D3DFMT_R32F] = PIPE_FORMAT_R32_FLOAT, + [D3DFMT_G16R16F] = PIPE_FORMAT_R16G16_FLOAT, + [D3DFMT_G32R32F] = PIPE_FORMAT_R32G32_FLOAT, + [D3DFMT_A16B16G16R16F] = PIPE_FORMAT_R16G16B16A16_FLOAT, + [D3DFMT_A32B32G32R32F] = PIPE_FORMAT_R32G32B32A32_FLOAT, + + /* non-1:1 formats (don't support because we'd have to convert) */ + [D3DFMT_R8G8B8] = PIPE_FORMAT_NONE, /* XXX order */ + [D3DFMT_A8R3G3B2] = PIPE_FORMAT_NONE, /* XXX alpha */ + /* This is ok because they're not lockable: */ + [D3DFMT_D15S1] = PIPE_FORMAT_Z24_UNORM_S8_UINT, + [D3DFMT_D24X4S4] = PIPE_FORMAT_Z24_UNORM_S8_UINT, + [D3DFMT_D24FS8] = PIPE_FORMAT_Z32_FLOAT_S8X24_UINT, + + /* not really formats */ + [D3DFMT_VERTEXDATA] = PIPE_FORMAT_NONE, + /* [D3DFMT_BINARYBUFFER] = PIPE_FORMAT_NONE, too large */ + + /* unsupported formats */ + [D3DFMT_L6V5U5] = PIPE_FORMAT_NONE, + [D3DFMT_X8L8V8U8] = PIPE_FORMAT_NONE, + + /* [D3DFMT_MULTI2_ARGB8] = PIPE_FORMAT_NONE, fourcc, MET */ + + [D3DFMT_CxV8U8] = PIPE_FORMAT_NONE, + [D3DFMT_A1] = PIPE_FORMAT_NONE, /* XXX: add this ? */ + [D3DFMT_A2B10G10R10_XR_BIAS] = PIPE_FORMAT_NONE, /* XXX ? */ +}; + +const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT] = +{ + [PIPE_FORMAT_NONE] = D3DFMT_UNKNOWN, + +/* [PIPE_FORMAT_B8G8R8_UNORM] = D3DFMT_R8G8B8, */ + [PIPE_FORMAT_B8G8R8A8_UNORM] = D3DFMT_A8R8G8B8, + [PIPE_FORMAT_B8G8R8X8_UNORM] = D3DFMT_X8R8G8B8, + [PIPE_FORMAT_B5G6R5_UNORM] = D3DFMT_R5G6B5, + [PIPE_FORMAT_B5G5R5X1_UNORM] = D3DFMT_X1R5G5B5, + [PIPE_FORMAT_B5G5R5A1_UNORM] = D3DFMT_A1R5G5B5, + [PIPE_FORMAT_B4G4R4A4_UNORM] = D3DFMT_A4R4G4B4, + [PIPE_FORMAT_B2G3R3_UNORM] = D3DFMT_R3G3B2, + [PIPE_FORMAT_A8_UNORM] = D3DFMT_A8, +/* [PIPE_FORMAT_B2G3R3A8_UNORM] = D3DFMT_A8R3G3B2, */ + [PIPE_FORMAT_B4G4R4X4_UNORM] = D3DFMT_X4R4G4B4, + [PIPE_FORMAT_R10G10B10A2_UNORM] = D3DFMT_A2B10G10R10, + [PIPE_FORMAT_R8G8B8A8_UNORM] = D3DFMT_A8B8G8R8, + [PIPE_FORMAT_R8G8B8X8_UNORM] = D3DFMT_X8B8G8R8, + [PIPE_FORMAT_R16G16_UNORM] = D3DFMT_G16R16, + [PIPE_FORMAT_B10G10R10A2_UNORM] = D3DFMT_A2R10G10B10, + [PIPE_FORMAT_R16G16B16A16_UNORM] = D3DFMT_A16B16G16R16, + + [PIPE_FORMAT_R8_UINT] = D3DFMT_P8, + [PIPE_FORMAT_R8A8_UINT] = D3DFMT_A8P8, + + [PIPE_FORMAT_L8_UNORM] = D3DFMT_L8, + [PIPE_FORMAT_L8A8_UNORM] = D3DFMT_A8L8, + [PIPE_FORMAT_L4A4_UNORM] = D3DFMT_A4L4, + + [PIPE_FORMAT_R8G8_SNORM] = D3DFMT_V8U8, +/* [PIPE_FORMAT_?] = D3DFMT_L6V5U5, */ +/* [PIPE_FORMAT_?] = D3DFMT_X8L8V8U8, */ + [PIPE_FORMAT_R8G8B8A8_SNORM] = D3DFMT_Q8W8V8U8, + [PIPE_FORMAT_R16G16_SNORM] = D3DFMT_V16U16, + [PIPE_FORMAT_R10SG10SB10SA2U_NORM] = D3DFMT_A2W10V10U10, + + [PIPE_FORMAT_YUYV] = D3DFMT_UYVY, +/* [PIPE_FORMAT_YUY2] = D3DFMT_YUY2, */ + [PIPE_FORMAT_DXT1_RGBA] = D3DFMT_DXT1, +/* [PIPE_FORMAT_DXT2_RGBA] = D3DFMT_DXT2, */ + [PIPE_FORMAT_DXT3_RGBA] = D3DFMT_DXT3, +/* [PIPE_FORMAT_DXT4_RGBA] = D3DFMT_DXT4, */ + [PIPE_FORMAT_DXT5_RGBA] = D3DFMT_DXT5, +/* [PIPE_FORMAT_?] = D3DFMT_MULTI2_ARGB8, (MET) */ + [PIPE_FORMAT_R8G8_B8G8_UNORM] = D3DFMT_R8G8_B8G8, /* XXX: order */ + [PIPE_FORMAT_G8R8_G8B8_UNORM] = D3DFMT_G8R8_G8B8, + + [PIPE_FORMAT_Z16_UNORM] = D3DFMT_D16_LOCKABLE, + [PIPE_FORMAT_Z32_UNORM] = D3DFMT_D32, +/* [PIPE_FORMAT_Z15_UNORM_S1_UINT] = D3DFMT_D15S1, */ + [PIPE_FORMAT_S8_UINT_Z24_UNORM] = D3DFMT_D24S8, + [PIPE_FORMAT_X8Z24_UNORM] = D3DFMT_D24X8, + [PIPE_FORMAT_L16_UNORM] = D3DFMT_L16, + [PIPE_FORMAT_Z32_FLOAT] = D3DFMT_D32F_LOCKABLE, +/* [PIPE_FORMAT_Z24_FLOAT_S8_UINT] = D3DFMT_D24FS8, */ + + [PIPE_FORMAT_R16_UINT] = D3DFMT_INDEX16, + [PIPE_FORMAT_R32_UINT] = D3DFMT_INDEX32, + [PIPE_FORMAT_R16G16B16A16_SNORM] = D3DFMT_Q16W16V16U16, + + [PIPE_FORMAT_R16_FLOAT] = D3DFMT_R16F, + [PIPE_FORMAT_R32_FLOAT] = D3DFMT_R32F, + [PIPE_FORMAT_R16G16_FLOAT] = D3DFMT_G16R16F, + [PIPE_FORMAT_R32G32_FLOAT] = D3DFMT_G32R32F, + [PIPE_FORMAT_R16G16B16A16_FLOAT] = D3DFMT_A16B16G16R16F, + [PIPE_FORMAT_R32G32B32A32_FLOAT] = D3DFMT_A32B32G32R32F, + +/* [PIPE_FORMAT_?] = D3DFMT_CxV8U8, */ +}; diff --git a/src/gallium/state_trackers/nine/nine_pipe.h b/src/gallium/state_trackers/nine/nine_pipe.h new file mode 100644 index 00000000000..1fd16944fd5 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_pipe.h @@ -0,0 +1,568 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_PIPE_H_ +#define _NINE_PIPE_H_ + +#include "d3d9.h" +#include "pipe/p_format.h" +#include "pipe/p_state.h" /* pipe_box */ +#include "util/u_rect.h" +#include "nine_helpers.h" + +struct cso_context; + +extern const enum pipe_format nine_d3d9_to_pipe_format_map[120]; +extern const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT]; + +void nine_convert_dsa_state(struct cso_context *, const DWORD *); +void nine_convert_rasterizer_state(struct cso_context *, const DWORD *); +void nine_convert_blend_state(struct cso_context *, const DWORD *); +void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *); + +void nine_pipe_context_clear(struct NineDevice9 *); + +static INLINE unsigned d3dlock_buffer_to_pipe_transfer_usage(DWORD Flags) +{ + unsigned usage; + + if (Flags & D3DLOCK_DISCARD) + usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; + else + if (Flags & D3DLOCK_READONLY) + usage = PIPE_TRANSFER_READ; + else + usage = PIPE_TRANSFER_READ_WRITE; + + if (Flags & D3DLOCK_NOOVERWRITE) + usage = (PIPE_TRANSFER_UNSYNCHRONIZED | + PIPE_TRANSFER_DISCARD_RANGE | usage) & ~PIPE_TRANSFER_READ; + else + if (Flags & D3DLOCK_DONOTWAIT) + usage |= PIPE_TRANSFER_DONTBLOCK; + + /* + if (Flags & D3DLOCK_NO_DIRTY_UPDATE) + usage |= PIPE_TRANSFER_FLUSH_EXPLICIT; + */ + + return usage; +} + +static INLINE void +rect_to_pipe_box(struct pipe_box *dst, const RECT *src) +{ + dst->x = src->left; + dst->y = src->top; + dst->z = 0; + dst->width = src->right - src->left; + dst->height = src->bottom - src->top; + dst->depth = 1; +} + +static INLINE boolean +rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src) +{ + rect_to_pipe_box(dst, src); + + if (dst->width <= 0 || dst->height <= 0) { + DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box"); + dst->width = MAX2(dst->width, 0); + dst->height = MAX2(dst->height, 0); + return TRUE; + } + return FALSE; +} + +static INLINE boolean +rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *src) +{ + rect_to_pipe_box(dst, src); + + if (dst->width >= 0 && dst->height >= 0) + return FALSE; + if (dst->width < 0) dst->width = -dst->width; + if (dst->height < 0) dst->height = -dst->height; + return TRUE; +} + +static INLINE void +nine_u_rect_to_pipe_box(struct pipe_box *dst, const struct u_rect *rect, int z) +{ + dst->x = rect->x0; + dst->y = rect->y0; + dst->z = z; + dst->width = rect->x1 - rect->x0; + dst->height = rect->y1 - rect->y0; + dst->depth = 1; +} + +static INLINE void +rect_to_pipe_box_xy_only(struct pipe_box *dst, const RECT *src) +{ + user_warn(src->left > src->right || src->top > src->bottom); + + dst->x = src->left; + dst->y = src->top; + dst->width = src->right - src->left; + dst->height = src->bottom - src->top; +} + +static INLINE boolean +rect_to_pipe_box_xy_only_clamp(struct pipe_box *dst, const RECT *src) +{ + rect_to_pipe_box_xy_only(dst, src); + + if (dst->width <= 0 || dst->height <= 0) { + DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box"); + dst->width = MAX2(dst->width, 0); + dst->height = MAX2(dst->height, 0); + return TRUE; + } + return FALSE; +} + +static INLINE void +rect_to_g3d_u_rect(struct u_rect *dst, const RECT *src) +{ + user_warn(src->left > src->right || src->top > src->bottom); + + dst->x0 = src->left; + dst->x1 = src->right; + dst->y0 = src->top; + dst->y1 = src->bottom; +} + +static INLINE void +d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src) +{ + user_warn(src->Left > src->Right); + user_warn(src->Top > src->Bottom); + user_warn(src->Front > src->Back); + + dst->x = src->Left; + dst->y = src->Top; + dst->z = src->Front; + dst->width = src->Right - src->Left; + dst->height = src->Bottom - src->Top; + dst->depth = src->Back - src->Front; +} + +static INLINE D3DFORMAT +pipe_to_d3d9_format(enum pipe_format format) +{ + return nine_pipe_to_d3d9_format_map[format]; +} + +static INLINE enum pipe_format +d3d9_to_pipe_format(D3DFORMAT format) +{ + if (format <= D3DFMT_A2B10G10R10_XR_BIAS) + return nine_d3d9_to_pipe_format_map[format]; + switch (format) { + case D3DFMT_INTZ: return PIPE_FORMAT_Z24_UNORM_S8_UINT; + case D3DFMT_DXT1: return PIPE_FORMAT_DXT1_RGBA; + case D3DFMT_DXT2: return PIPE_FORMAT_DXT3_RGBA; /* XXX */ + case D3DFMT_DXT3: return PIPE_FORMAT_DXT3_RGBA; + case D3DFMT_DXT4: return PIPE_FORMAT_DXT5_RGBA; /* XXX */ + case D3DFMT_DXT5: return PIPE_FORMAT_DXT5_RGBA; + case D3DFMT_UYVY: return PIPE_FORMAT_UYVY; + case D3DFMT_YUY2: return PIPE_FORMAT_YUYV; /* XXX check */ + case D3DFMT_NV12: return PIPE_FORMAT_NV12; + case D3DFMT_G8R8_G8B8: return PIPE_FORMAT_G8R8_G8B8_UNORM; /* XXX order ? */ + case D3DFMT_R8G8_B8G8: return PIPE_FORMAT_R8G8_B8G8_UNORM; /* XXX order ? */ + case D3DFMT_BINARYBUFFER: return PIPE_FORMAT_NONE; /* not a format */ + case D3DFMT_MULTI2_ARGB8: return PIPE_FORMAT_NONE; /* not supported */ + case D3DFMT_Y210: /* XXX */ + case D3DFMT_Y216: + case D3DFMT_NV11: + case D3DFMT_DF16: /* useless, not supported by wine either */ + case D3DFMT_DF24: /* useless, not supported by wine either */ + case D3DFMT_NULL: /* special cased, only for surfaces */ + return PIPE_FORMAT_NONE; + default: + DBG_FLAG(DBG_UNKNOWN, "unknown D3DFORMAT: 0x%x/%c%c%c%c\n", + format, (char)format, (char)(format >> 8), + (char)(format >> 16), (char)(format >> 24)); + return PIPE_FORMAT_NONE; + } +} + +static INLINE const char * +d3dformat_to_string(D3DFORMAT fmt) +{ + switch (fmt) { + case D3DFMT_UNKNOWN: return "D3DFMT_UNKNOWN"; + case D3DFMT_R8G8B8: return "D3DFMT_R8G8B8"; + case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8"; + case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8"; + case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5"; + case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5"; + case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5"; + case D3DFMT_A4R4G4B4: return "D3DFMT_A4R4G4B4"; + case D3DFMT_R3G3B2: return "D3DFMT_R3G3B2"; + case D3DFMT_A8: return "D3DFMT_A8"; + case D3DFMT_A8R3G3B2: return "D3DFMT_A8R3G3B2"; + case D3DFMT_X4R4G4B4: return "D3DFMT_X4R4G4B4"; + case D3DFMT_A2B10G10R10: return "D3DFMT_A2B10G10R10"; + case D3DFMT_A8B8G8R8: return "D3DFMT_A8B8G8R8"; + case D3DFMT_X8B8G8R8: return "D3DFMT_X8B8G8R8"; + case D3DFMT_G16R16: return "D3DFMT_G16R16"; + case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10"; + case D3DFMT_A16B16G16R16: return "D3DFMT_A16B16G16R16"; + case D3DFMT_A8P8: return "D3DFMT_A8P8"; + case D3DFMT_P8: return "D3DFMT_P8"; + case D3DFMT_L8: return "D3DFMT_L8"; + case D3DFMT_A8L8: return "D3DFMT_A8L8"; + case D3DFMT_A4L4: return "D3DFMT_A4L4"; + case D3DFMT_V8U8: return "D3DFMT_V8U8"; + case D3DFMT_L6V5U5: return "D3DFMT_L6V5U5"; + case D3DFMT_X8L8V8U8: return "D3DFMT_X8L8V8U8"; + case D3DFMT_Q8W8V8U8: return "D3DFMT_Q8W8V8U8"; + case D3DFMT_V16U16: return "D3DFMT_V16U16"; + case D3DFMT_A2W10V10U10: return "D3DFMT_A2W10V10U10"; + case D3DFMT_UYVY: return "D3DFMT_UYVY"; + case D3DFMT_R8G8_B8G8: return "D3DFMT_R8G8_B8G8"; + case D3DFMT_YUY2: return "D3DFMT_YUY2"; + case D3DFMT_G8R8_G8B8: return "D3DFMT_G8R8_G8B8"; + case D3DFMT_DXT1: return "D3DFMT_DXT1"; + case D3DFMT_DXT2: return "D3DFMT_DXT2"; + case D3DFMT_DXT3: return "D3DFMT_DXT3"; + case D3DFMT_DXT4: return "D3DFMT_DXT4"; + case D3DFMT_DXT5: return "D3DFMT_DXT5"; + case D3DFMT_D16_LOCKABLE: return "D3DFMT_D16_LOCKABLE"; + case D3DFMT_D32: return "D3DFMT_D32"; + case D3DFMT_D15S1: return "D3DFMT_D15S1"; + case D3DFMT_D24S8: return "D3DFMT_D24S8"; + case D3DFMT_D24X8: return "D3DFMT_D24X8"; + case D3DFMT_D24X4S4: return "D3DFMT_D24X4S4"; + case D3DFMT_D16: return "D3DFMT_D16"; + case D3DFMT_D32F_LOCKABLE: return "D3DFMT_D32F_LOCKABLE"; + case D3DFMT_D24FS8: return "D3DFMT_D24FS8"; + case D3DFMT_D32_LOCKABLE: return "D3DFMT_D32_LOCKABLE"; + case D3DFMT_S8_LOCKABLE: return "D3DFMT_S8_LOCKABLE"; + case D3DFMT_L16: return "D3DFMT_L16"; + case D3DFMT_VERTEXDATA: return "D3DFMT_VERTEXDATA"; + case D3DFMT_INDEX16: return "D3DFMT_INDEX16"; + case D3DFMT_INDEX32: return "D3DFMT_INDEX32"; + case D3DFMT_Q16W16V16U16: return "D3DFMT_Q16W16V16U16"; + case D3DFMT_MULTI2_ARGB8: return "D3DFMT_MULTI2_ARGB8"; + case D3DFMT_R16F: return "D3DFMT_R16F"; + case D3DFMT_G16R16F: return "D3DFMT_G16R16F"; + case D3DFMT_A16B16G16R16F: return "D3DFMT_A16B16G16R16F"; + case D3DFMT_R32F: return "D3DFMT_R32F"; + case D3DFMT_G32R32F: return "D3DFMT_G32R32F"; + case D3DFMT_A32B32G32R32F: return "D3DFMT_A32B32G32R32F"; + case D3DFMT_CxV8U8: return "D3DFMT_CxV8U8"; + case D3DFMT_A1: return "D3DFMT_A1"; + case D3DFMT_A2B10G10R10_XR_BIAS: return "D3DFMT_A2B10G10R10_XR_BIAS"; + case D3DFMT_BINARYBUFFER: return "D3DFMT_BINARYBUFFER"; + case D3DFMT_DF16: return "D3DFMT_DF16"; + case D3DFMT_DF24: return "D3DFMT_DF24"; + case D3DFMT_INTZ: return "D3DFMT_INTZ"; + case D3DFMT_NULL: return "D3DFMT_NULL"; + default: + break; + } + return "Unknown"; +} + +static INLINE unsigned +nine_fvf_stride( DWORD fvf ) +{ + unsigned texcount, i, size = 0; + + switch (fvf & D3DFVF_POSITION_MASK) { + case D3DFVF_XYZ: size += 3*4; break; + case D3DFVF_XYZRHW: size += 4*4; break; + case D3DFVF_XYZB1: size += 4*4; break; + case D3DFVF_XYZB2: size += 5*4; break; + case D3DFVF_XYZB3: size += 6*4; break; + case D3DFVF_XYZB4: size += 7*4; break; + case D3DFVF_XYZB5: size += 8*4; break; + case D3DFVF_XYZW: size += 4*4; break; + default: + user_warn("Position doesn't match any known combination."); + break; + } + + if (fvf & D3DFVF_NORMAL) { size += 3*4; } + if (fvf & D3DFVF_PSIZE) { size += 1*4; } + if (fvf & D3DFVF_DIFFUSE) { size += 1*4; } + if (fvf & D3DFVF_SPECULAR) { size += 1*4; } + + texcount = (fvf >> D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK; + if (user_error(texcount <= 8)) + texcount = 8; + + for (i = 0; i < texcount; ++i) { + unsigned texformat = (fvf>>(16+i*2))&0x3; + /* texformats are defined having been shifted around so 1=3,2=0,3=1,4=2 + * meaning we can just do this instead of the switch below */ + size += (((texformat+1)&0x3)+1)*4; + + /* + switch (texformat) { + case D3DFVF_TEXTUREFORMAT1: size += 1*4; + case D3DFVF_TEXTUREFORMAT2: size += 2*4; + case D3DFVF_TEXTUREFORMAT3: size += 3*4; + case D3DFVF_TEXTUREFORMAT4: size += 4*4; + } + */ + } + + return size; +} + +static INLINE void +d3dcolor_to_rgba(float *rgba, D3DCOLOR color) +{ + rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF; + rgba[1] = (float)((color >> 8) & 0xFF) / 0xFF; + rgba[2] = (float)((color >> 0) & 0xFF) / 0xFF; + rgba[3] = (float)((color >> 24) & 0xFF) / 0xFF; +} + +static INLINE void +d3dcolor_to_pipe_color_union(union pipe_color_union *rgba, D3DCOLOR color) +{ + d3dcolor_to_rgba(&rgba->f[0], color); +} + +static INLINE unsigned +d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim) +{ + switch (prim) { + case D3DPT_POINTLIST: return PIPE_PRIM_POINTS; + case D3DPT_LINELIST: return PIPE_PRIM_LINES; + case D3DPT_LINESTRIP: return PIPE_PRIM_LINE_STRIP; + case D3DPT_TRIANGLELIST: return PIPE_PRIM_TRIANGLES; + case D3DPT_TRIANGLESTRIP: return PIPE_PRIM_TRIANGLE_STRIP; + case D3DPT_TRIANGLEFAN: return PIPE_PRIM_TRIANGLE_FAN; + default: + assert(0); + return PIPE_PRIM_POINTS; + } +} + +static INLINE unsigned +prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count) +{ + switch (prim) { + case D3DPT_POINTLIST: return count; + case D3DPT_LINELIST: return count * 2; + case D3DPT_LINESTRIP: return count + 1; + case D3DPT_TRIANGLELIST: return count * 3; + case D3DPT_TRIANGLESTRIP: return count + 2; + case D3DPT_TRIANGLEFAN: return count + 2; + default: + assert(0); + return 0; + } +} + +static INLINE unsigned +d3dcmpfunc_to_pipe_func(D3DCMPFUNC func) +{ + switch (func) { + case D3DCMP_NEVER: return PIPE_FUNC_NEVER; + case D3DCMP_LESS: return PIPE_FUNC_LESS; + case D3DCMP_EQUAL: return PIPE_FUNC_EQUAL; + case D3DCMP_LESSEQUAL: return PIPE_FUNC_LEQUAL; + case D3DCMP_GREATER: return PIPE_FUNC_GREATER; + case D3DCMP_NOTEQUAL: return PIPE_FUNC_NOTEQUAL; + case D3DCMP_GREATEREQUAL: return PIPE_FUNC_GEQUAL; + case D3DCMP_ALWAYS: return PIPE_FUNC_ALWAYS; + default: + assert(0); + return PIPE_FUNC_NEVER; + } +} + +static INLINE unsigned +d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op) +{ + switch (op) { + case D3DSTENCILOP_KEEP: return PIPE_STENCIL_OP_KEEP; + case D3DSTENCILOP_ZERO: return PIPE_STENCIL_OP_ZERO; + case D3DSTENCILOP_REPLACE: return PIPE_STENCIL_OP_REPLACE; + case D3DSTENCILOP_INCRSAT: return PIPE_STENCIL_OP_INCR; + case D3DSTENCILOP_DECRSAT: return PIPE_STENCIL_OP_DECR; + case D3DSTENCILOP_INVERT: return PIPE_STENCIL_OP_INVERT; + case D3DSTENCILOP_INCR: return PIPE_STENCIL_OP_INCR_WRAP; + case D3DSTENCILOP_DECR: return PIPE_STENCIL_OP_DECR_WRAP; + default: + return PIPE_STENCIL_OP_ZERO; + } +} + +static INLINE unsigned +d3dcull_to_pipe_face(D3DCULL cull) +{ + switch (cull) { + case D3DCULL_NONE: return PIPE_FACE_NONE; + case D3DCULL_CW: return PIPE_FACE_FRONT; + case D3DCULL_CCW: return PIPE_FACE_BACK; + default: + assert(0); + return PIPE_FACE_NONE; + } +} + +static INLINE unsigned +d3dfillmode_to_pipe_polygon_mode(D3DFILLMODE mode) +{ + switch (mode) { + case D3DFILL_POINT: return PIPE_POLYGON_MODE_POINT; + case D3DFILL_WIREFRAME: return PIPE_POLYGON_MODE_LINE; + case D3DFILL_SOLID: return PIPE_POLYGON_MODE_FILL; + default: + assert(0); + return PIPE_POLYGON_MODE_FILL; + } +} + +static INLINE unsigned +d3dblendop_to_pipe_blend(D3DBLENDOP op) +{ + switch (op) { + case D3DBLENDOP_ADD: return PIPE_BLEND_ADD; + case D3DBLENDOP_SUBTRACT: return PIPE_BLEND_SUBTRACT; + case D3DBLENDOP_REVSUBTRACT: return PIPE_BLEND_REVERSE_SUBTRACT; + case D3DBLENDOP_MIN: return PIPE_BLEND_MIN; + case D3DBLENDOP_MAX: return PIPE_BLEND_MAX; + default: + assert(0); + return PIPE_BLEND_ADD; + } +} + +/* NOTE: The COLOR factors for are equal to the ALPHA ones for alpha. + * Drivers may check RGB and ALPHA factors for equality so we should not + * simply substitute the ALPHA variants. + */ +static INLINE unsigned +d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b) +{ + switch (b) { + case D3DBLEND_ZERO: return PIPE_BLENDFACTOR_ZERO; + case D3DBLEND_ONE: return PIPE_BLENDFACTOR_ONE; + case D3DBLEND_SRCCOLOR: return PIPE_BLENDFACTOR_SRC_COLOR/*ALPHA*/; + case D3DBLEND_INVSRCCOLOR: return PIPE_BLENDFACTOR_INV_SRC_COLOR/*ALPHA*/; + case D3DBLEND_SRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; + case D3DBLEND_INVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case D3DBLEND_DESTALPHA: return PIPE_BLENDFACTOR_DST_ALPHA; + case D3DBLEND_INVDESTALPHA: return PIPE_BLENDFACTOR_INV_DST_ALPHA; + case D3DBLEND_DESTCOLOR: return PIPE_BLENDFACTOR_DST_COLOR/*ALPHA*/; + case D3DBLEND_INVDESTCOLOR: return PIPE_BLENDFACTOR_INV_DST_COLOR/*ALPHA*/; + case D3DBLEND_SRCALPHASAT: return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; + case D3DBLEND_BOTHSRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; + case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case D3DBLEND_BLENDFACTOR: return PIPE_BLENDFACTOR_CONST_COLOR/*ALPHA*/; + case D3DBLEND_INVBLENDFACTOR: return PIPE_BLENDFACTOR_INV_CONST_COLOR/*ALPHA*/; + case D3DBLEND_SRCCOLOR2: return PIPE_BLENDFACTOR_ONE; /* XXX */ + case D3DBLEND_INVSRCCOLOR2: return PIPE_BLENDFACTOR_ZERO; /* XXX */ + default: + DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b); + return PIPE_BLENDFACTOR_ZERO; + } +} + +static INLINE unsigned +d3dblend_color_to_pipe_blendfactor(D3DBLEND b) +{ + switch (b) { + case D3DBLEND_ZERO: return PIPE_BLENDFACTOR_ZERO; + case D3DBLEND_ONE: return PIPE_BLENDFACTOR_ONE; + case D3DBLEND_SRCCOLOR: return PIPE_BLENDFACTOR_SRC_COLOR; + case D3DBLEND_INVSRCCOLOR: return PIPE_BLENDFACTOR_INV_SRC_COLOR; + case D3DBLEND_SRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; + case D3DBLEND_INVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case D3DBLEND_DESTALPHA: return PIPE_BLENDFACTOR_DST_ALPHA; + case D3DBLEND_INVDESTALPHA: return PIPE_BLENDFACTOR_INV_DST_ALPHA; + case D3DBLEND_DESTCOLOR: return PIPE_BLENDFACTOR_DST_COLOR; + case D3DBLEND_INVDESTCOLOR: return PIPE_BLENDFACTOR_INV_DST_COLOR; + case D3DBLEND_SRCALPHASAT: return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; + case D3DBLEND_BOTHSRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; + case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case D3DBLEND_BLENDFACTOR: return PIPE_BLENDFACTOR_CONST_COLOR; + case D3DBLEND_INVBLENDFACTOR: return PIPE_BLENDFACTOR_INV_CONST_COLOR; + case D3DBLEND_SRCCOLOR2: return PIPE_BLENDFACTOR_SRC1_COLOR; + case D3DBLEND_INVSRCCOLOR2: return PIPE_BLENDFACTOR_INV_SRC1_COLOR; + default: + DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b); + return PIPE_BLENDFACTOR_ZERO; + } +} + +static INLINE unsigned +d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr) +{ + switch (addr) { + case D3DTADDRESS_WRAP: return PIPE_TEX_WRAP_REPEAT; + case D3DTADDRESS_MIRROR: return PIPE_TEX_WRAP_MIRROR_REPEAT; + case D3DTADDRESS_CLAMP: return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + case D3DTADDRESS_BORDER: return PIPE_TEX_WRAP_CLAMP_TO_BORDER; + case D3DTADDRESS_MIRRORONCE: return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + default: + assert(0); + return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + } +} + +static INLINE unsigned +d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter) +{ + switch (filter) { + case D3DTEXF_POINT: return PIPE_TEX_FILTER_NEAREST; + case D3DTEXF_LINEAR: return PIPE_TEX_FILTER_LINEAR; + case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR; + + case D3DTEXF_NONE: + case D3DTEXF_PYRAMIDALQUAD: + case D3DTEXF_GAUSSIANQUAD: + case D3DTEXF_CONVOLUTIONMONO: + default: + assert(0); + return PIPE_TEX_FILTER_NEAREST; + } +} + +static INLINE unsigned +d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter) +{ + switch (filter) { + case D3DTEXF_NONE: return PIPE_TEX_MIPFILTER_NONE; + case D3DTEXF_POINT: return PIPE_TEX_FILTER_NEAREST; + case D3DTEXF_LINEAR: return PIPE_TEX_FILTER_LINEAR; + case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR; + + case D3DTEXF_PYRAMIDALQUAD: + case D3DTEXF_GAUSSIANQUAD: + case D3DTEXF_CONVOLUTIONMONO: + default: + assert(0); + return PIPE_TEX_MIPFILTER_NONE; + } +} + +#endif /* _NINE_PIPE_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_quirk.c b/src/gallium/state_trackers/nine/nine_quirk.c new file mode 100644 index 00000000000..267436b14de --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_quirk.c @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_quirk.h" + +#include "util/u_debug.h" + +static const struct debug_named_value nine_quirk_table[] = { + { "fakecaps", QUIRK_FAKE_CAPS, + "Fake caps to emulate D3D specs regardless of hardware caps." }, + { "lenientshader", QUIRK_LENIENT_SHADER, + "Be lenient when translating shaders." }, + { "all", ~0U, + "Enable all quirks." }, + DEBUG_NAMED_VALUE_END +}; + +boolean +_nine_get_quirk( unsigned quirk ) +{ + static boolean first = TRUE; + static unsigned long flags = 0; + + if (first) { + first = FALSE; + flags = debug_get_flags_option("NINE_QUIRKS", nine_quirk_table, 0); + } + + return !!(flags & quirk); +} diff --git a/src/gallium/state_trackers/nine/nine_quirk.h b/src/gallium/state_trackers/nine/nine_quirk.h new file mode 100644 index 00000000000..9c082dd9f93 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_quirk.h @@ -0,0 +1,36 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_QUIRK_H_ +#define _NINE_QUIRK_H_ + +#include "pipe/p_compiler.h" + +boolean +_nine_get_quirk( unsigned quirk ); + +#define QUIRK(q) (_nine_get_quirk(QUIRK_##q)) + +#define QUIRK_FAKE_CAPS 0x00000001 +#define QUIRK_LENIENT_SHADER 0x00000002 + +#endif /* _NINE_QUIRK_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_shader.c b/src/gallium/state_trackers/nine/nine_shader.c new file mode 100644 index 00000000000..c5b1ccbc5cd --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_shader.c @@ -0,0 +1,2959 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * Copyright 2013 Christoph Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_shader.h" + +#include "device9.h" +#include "nine_debug.h" +#include "nine_state.h" + +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_ureg.h" +#include "tgsi/tgsi_dump.h" + +#define DBG_CHANNEL DBG_SHADER + +#if 1 +#define NINE_TGSI_LAZY_DEVS /* don't use TGSI_OPCODE_BREAKC */ +#endif +#define NINE_TGSI_LAZY_R600 /* don't use TGSI_OPCODE_DP2A */ + +#define DUMP(args...) _nine_debug_printf(DBG_CHANNEL, NULL, args) + + +struct shader_translator; + +typedef HRESULT (*translate_instruction_func)(struct shader_translator *); + +static INLINE const char *d3dsio_to_string(unsigned opcode); + + +#define NINED3D_SM1_VS 0xfffe +#define NINED3D_SM1_PS 0xffff + +#define NINE_MAX_COND_DEPTH 64 +#define NINE_MAX_LOOP_DEPTH 64 + +#define NINED3DSP_END 0x0000ffff + +#define NINED3DSPTYPE_FLOAT4 0 +#define NINED3DSPTYPE_INT4 1 +#define NINED3DSPTYPE_BOOL 2 + +#define NINED3DSPR_IMMEDIATE (D3DSPR_PREDICATE + 1) + +#define NINED3DSP_WRITEMASK_MASK D3DSP_WRITEMASK_ALL +#define NINED3DSP_WRITEMASK_SHIFT 16 + +#define NINED3DSHADER_INST_PREDICATED (1 << 28) + +#define NINED3DSHADER_REL_OP_GT 1 +#define NINED3DSHADER_REL_OP_EQ 2 +#define NINED3DSHADER_REL_OP_GE 3 +#define NINED3DSHADER_REL_OP_LT 4 +#define NINED3DSHADER_REL_OP_NE 5 +#define NINED3DSHADER_REL_OP_LE 6 + +#define NINED3DSIO_OPCODE_FLAGS_SHIFT 16 +#define NINED3DSIO_OPCODE_FLAGS_MASK (0xff << NINED3DSIO_OPCODE_FLAGS_SHIFT) + +#define NINED3DSI_TEXLD_PROJECT 0x1 +#define NINED3DSI_TEXLD_BIAS 0x2 + +#define NINED3DSP_WRITEMASK_0 0x1 +#define NINED3DSP_WRITEMASK_1 0x2 +#define NINED3DSP_WRITEMASK_2 0x4 +#define NINED3DSP_WRITEMASK_3 0x8 +#define NINED3DSP_WRITEMASK_ALL 0xf + +#define NINED3DSP_NOSWIZZLE ((0 << 0) | (1 << 2) | (2 << 4) | (3 << 6)) + +#define NINE_SWIZZLE4(x,y,z,w) \ + TGSI_SWIZZLE_##x, TGSI_SWIZZLE_##y, TGSI_SWIZZLE_##z, TGSI_SWIZZLE_##w + +#define NINED3DSPDM_SATURATE (D3DSPDM_SATURATE >> D3DSP_DSTMOD_SHIFT) +#define NINED3DSPDM_PARTIALP (D3DSPDM_PARTIALPRECISION >> D3DSP_DSTMOD_SHIFT) +#define NINED3DSPDM_CENTROID (D3DSPDM_MSAMPCENTROID >> D3DSP_DSTMOD_SHIFT) + +/* + * NEG all, not ps: m3x2, m3x3, m3x4, m4x3, m4x4 + * BIAS <= PS 1.4 (x-0.5) + * BIASNEG <= PS 1.4 (-(x-0.5)) + * SIGN <= PS 1.4 (2(x-0.5)) + * SIGNNEG <= PS 1.4 (-2(x-0.5)) + * COMP <= PS 1.4 (1-x) + * X2 = PS 1.4 (2x) + * X2NEG = PS 1.4 (-2x) + * DZ <= PS 1.4, tex{ld,crd} (.xy/.z), z=0 => .11 + * DW <= PS 1.4, tex{ld,crd} (.xy/.w), w=0 => .11 + * ABS >= SM 3.0 (abs(x)) + * ABSNEG >= SM 3.0 (-abs(x)) + * NOT >= SM 2.0 pedication only + */ +#define NINED3DSPSM_NONE (D3DSPSM_NONE >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_NEG (D3DSPSM_NEG >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_BIAS (D3DSPSM_BIAS >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_BIASNEG (D3DSPSM_BIASNEG >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_SIGN (D3DSPSM_SIGN >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_SIGNNEG (D3DSPSM_SIGNNEG >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_COMP (D3DSPSM_COMP >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_X2 (D3DSPSM_X2 >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_X2NEG (D3DSPSM_X2NEG >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_DZ (D3DSPSM_DZ >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_DW (D3DSPSM_DW >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_ABS (D3DSPSM_ABS >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_ABSNEG (D3DSPSM_ABSNEG >> D3DSP_SRCMOD_SHIFT) +#define NINED3DSPSM_NOT (D3DSPSM_NOT >> D3DSP_SRCMOD_SHIFT) + +static const char *sm1_mod_str[] = +{ + [NINED3DSPSM_NONE] = "", + [NINED3DSPSM_NEG] = "-", + [NINED3DSPSM_BIAS] = "bias", + [NINED3DSPSM_BIASNEG] = "biasneg", + [NINED3DSPSM_SIGN] = "sign", + [NINED3DSPSM_SIGNNEG] = "signneg", + [NINED3DSPSM_COMP] = "comp", + [NINED3DSPSM_X2] = "x2", + [NINED3DSPSM_X2NEG] = "x2neg", + [NINED3DSPSM_DZ] = "dz", + [NINED3DSPSM_DW] = "dw", + [NINED3DSPSM_ABS] = "abs", + [NINED3DSPSM_ABSNEG] = "-abs", + [NINED3DSPSM_NOT] = "not" +}; + +static void +sm1_dump_writemask(BYTE mask) +{ + if (mask & 1) DUMP("x"); else DUMP("_"); + if (mask & 2) DUMP("y"); else DUMP("_"); + if (mask & 4) DUMP("z"); else DUMP("_"); + if (mask & 8) DUMP("w"); else DUMP("_"); +} + +static void +sm1_dump_swizzle(BYTE s) +{ + char c[4] = { 'x', 'y', 'z', 'w' }; + DUMP("%c%c%c%c", + c[(s >> 0) & 3], c[(s >> 2) & 3], c[(s >> 4) & 3], c[(s >> 6) & 3]); +} + +static const char sm1_file_char[] = +{ + [D3DSPR_TEMP] = 'r', + [D3DSPR_INPUT] = 'v', + [D3DSPR_CONST] = 'c', + [D3DSPR_ADDR] = 'A', + [D3DSPR_RASTOUT] = 'R', + [D3DSPR_ATTROUT] = 'D', + [D3DSPR_OUTPUT] = 'o', + [D3DSPR_CONSTINT] = 'I', + [D3DSPR_COLOROUT] = 'C', + [D3DSPR_DEPTHOUT] = 'D', + [D3DSPR_SAMPLER] = 's', + [D3DSPR_CONST2] = 'c', + [D3DSPR_CONST3] = 'c', + [D3DSPR_CONST4] = 'c', + [D3DSPR_CONSTBOOL] = 'B', + [D3DSPR_LOOP] = 'L', + [D3DSPR_TEMPFLOAT16] = 'h', + [D3DSPR_MISCTYPE] = 'M', + [D3DSPR_LABEL] = 'X', + [D3DSPR_PREDICATE] = 'p' +}; + +static void +sm1_dump_reg(BYTE file, INT index) +{ + switch (file) { + case D3DSPR_LOOP: + DUMP("aL"); + break; + case D3DSPR_COLOROUT: + DUMP("oC%i", index); + break; + case D3DSPR_DEPTHOUT: + DUMP("oDepth"); + break; + case D3DSPR_RASTOUT: + DUMP("oRast%i", index); + break; + case D3DSPR_CONSTINT: + DUMP("iconst[%i]", index); + break; + case D3DSPR_CONSTBOOL: + DUMP("bconst[%i]", index); + break; + default: + DUMP("%c%i", sm1_file_char[file], index); + break; + } +} + +struct sm1_src_param +{ + INT idx; + struct sm1_src_param *rel; + BYTE file; + BYTE swizzle; + BYTE mod; + BYTE type; + union { + DWORD d[4]; + float f[4]; + int i[4]; + BOOL b; + } imm; +}; +static void +sm1_parse_immediate(struct shader_translator *, struct sm1_src_param *); + +struct sm1_dst_param +{ + INT idx; + struct sm1_src_param *rel; + BYTE file; + BYTE mask; + BYTE mod; + BYTE shift; /* sint4 */ + BYTE type; +}; + +static INLINE void +assert_replicate_swizzle(const struct ureg_src *reg) +{ + assert(reg->SwizzleY == reg->SwizzleX && + reg->SwizzleZ == reg->SwizzleX && + reg->SwizzleW == reg->SwizzleX); +} + +static void +sm1_dump_immediate(const struct sm1_src_param *param) +{ + switch (param->type) { + case NINED3DSPTYPE_FLOAT4: + DUMP("{ %f %f %f %f }", + param->imm.f[0], param->imm.f[1], + param->imm.f[2], param->imm.f[3]); + break; + case NINED3DSPTYPE_INT4: + DUMP("{ %i %i %i %i }", + param->imm.i[0], param->imm.i[1], + param->imm.i[2], param->imm.i[3]); + break; + case NINED3DSPTYPE_BOOL: + DUMP("%s", param->imm.b ? "TRUE" : "FALSE"); + break; + default: + assert(0); + break; + } +} + +static void +sm1_dump_src_param(const struct sm1_src_param *param) +{ + if (param->file == NINED3DSPR_IMMEDIATE) { + assert(!param->mod && + !param->rel && + param->swizzle == NINED3DSP_NOSWIZZLE); + sm1_dump_immediate(param); + return; + } + + if (param->mod) + DUMP("%s(", sm1_mod_str[param->mod]); + if (param->rel) { + DUMP("%c[", sm1_file_char[param->file]); + sm1_dump_src_param(param->rel); + DUMP("+%i]", param->idx); + } else { + sm1_dump_reg(param->file, param->idx); + } + if (param->mod) + DUMP(")"); + if (param->swizzle != NINED3DSP_NOSWIZZLE) { + DUMP("."); + sm1_dump_swizzle(param->swizzle); + } +} + +static void +sm1_dump_dst_param(const struct sm1_dst_param *param) +{ + if (param->mod & NINED3DSPDM_SATURATE) + DUMP("sat "); + if (param->mod & NINED3DSPDM_PARTIALP) + DUMP("pp "); + if (param->mod & NINED3DSPDM_CENTROID) + DUMP("centroid "); + if (param->shift < 0) + DUMP("/%u ", 1 << -param->shift); + if (param->shift > 0) + DUMP("*%u ", 1 << param->shift); + + if (param->rel) { + DUMP("%c[", sm1_file_char[param->file]); + sm1_dump_src_param(param->rel); + DUMP("+%i]", param->idx); + } else { + sm1_dump_reg(param->file, param->idx); + } + if (param->mask != NINED3DSP_WRITEMASK_ALL) { + DUMP("."); + sm1_dump_writemask(param->mask); + } +} + +struct sm1_semantic +{ + struct sm1_dst_param reg; + BYTE sampler_type; + D3DDECLUSAGE usage; + BYTE usage_idx; +}; + +struct sm1_op_info +{ + /* NOTE: 0 is a valid TGSI opcode, but if handler is set, this parameter + * should be ignored completely */ + unsigned sio; + unsigned opcode; /* TGSI_OPCODE_x */ + + /* versions are still set even handler is set */ + struct { + unsigned min; + unsigned max; + } vert_version, frag_version; + + /* number of regs parsed outside of special handler */ + unsigned ndst; + unsigned nsrc; + + /* some instructions don't map perfectly, so use a special handler */ + translate_instruction_func handler; +}; + +struct sm1_instruction +{ + D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode; + BYTE flags; + BOOL coissue; + BOOL predicated; + BYTE ndst; + BYTE nsrc; + struct sm1_src_param src[4]; + struct sm1_src_param src_rel[4]; + struct sm1_src_param pred; + struct sm1_src_param dst_rel[1]; + struct sm1_dst_param dst[1]; + + struct sm1_op_info *info; +}; + +static void +sm1_dump_instruction(struct sm1_instruction *insn, unsigned indent) +{ + unsigned i; + + /* no info stored for these: */ + if (insn->opcode == D3DSIO_DCL) + return; + for (i = 0; i < indent; ++i) + DUMP(" "); + + if (insn->predicated) { + DUMP("@"); + sm1_dump_src_param(&insn->pred); + DUMP(" "); + } + DUMP("%s", d3dsio_to_string(insn->opcode)); + if (insn->flags) { + switch (insn->opcode) { + case D3DSIO_TEX: + DUMP(insn->flags == NINED3DSI_TEXLD_PROJECT ? "p" : "b"); + break; + default: + DUMP("_%x", insn->flags); + break; + } + } + if (insn->coissue) + DUMP("_co"); + DUMP(" "); + + for (i = 0; i < insn->ndst && i < Elements(insn->dst); ++i) { + sm1_dump_dst_param(&insn->dst[i]); + DUMP(" "); + } + + for (i = 0; i < insn->nsrc && i < Elements(insn->src); ++i) { + sm1_dump_src_param(&insn->src[i]); + DUMP(" "); + } + if (insn->opcode == D3DSIO_DEF || + insn->opcode == D3DSIO_DEFI || + insn->opcode == D3DSIO_DEFB) + sm1_dump_immediate(&insn->src[0]); + + DUMP("\n"); +} + +struct sm1_local_const +{ + INT idx; + struct ureg_src reg; + union { + boolean b; + float f[4]; + int32_t i[4]; + } imm; +}; + +struct shader_translator +{ + const DWORD *byte_code; + const DWORD *parse; + const DWORD *parse_next; + + struct ureg_program *ureg; + + /* shader version */ + struct { + BYTE major; + BYTE minor; + } version; + unsigned processor; /* TGSI_PROCESSOR_VERTEX/FRAMGENT */ + + boolean native_integers; + boolean inline_subroutines; + boolean lower_preds; + boolean want_texcoord; + boolean shift_wpos; + unsigned texcoord_sn; + + struct sm1_instruction insn; /* current instruction */ + + struct { + struct ureg_dst *r; + struct ureg_dst oPos; + struct ureg_dst oFog; + struct ureg_dst oPts; + struct ureg_dst oCol[4]; + struct ureg_dst o[PIPE_MAX_SHADER_OUTPUTS]; + struct ureg_dst oDepth; + struct ureg_src v[PIPE_MAX_SHADER_INPUTS]; + struct ureg_src vPos; + struct ureg_src vFace; + struct ureg_src s; + struct ureg_dst p; + struct ureg_dst a; + struct ureg_dst tS[8]; /* texture stage registers */ + struct ureg_dst tdst; /* scratch dst if we need extra modifiers */ + struct ureg_dst t[5]; /* scratch TEMPs */ + struct ureg_src vC[2]; /* PS color in */ + struct ureg_src vT[8]; /* PS texcoord in */ + struct ureg_dst rL[NINE_MAX_LOOP_DEPTH]; /* loop ctr */ + struct ureg_dst aL[NINE_MAX_LOOP_DEPTH]; /* loop ctr ADDR register */ + } regs; + unsigned num_temp; /* Elements(regs.r) */ + unsigned num_scratch; + unsigned loop_depth; + unsigned loop_depth_max; + unsigned cond_depth; + unsigned loop_labels[NINE_MAX_LOOP_DEPTH]; + unsigned cond_labels[NINE_MAX_COND_DEPTH]; + + unsigned *inst_labels; /* LABEL op */ + unsigned num_inst_labels; + + unsigned sampler_targets[NINE_MAX_SAMPLERS]; /* TGSI_TEXTURE_x */ + + struct sm1_local_const *lconstf; + unsigned num_lconstf; + struct sm1_local_const lconsti[NINE_MAX_CONST_I]; + struct sm1_local_const lconstb[NINE_MAX_CONST_B]; + + boolean indirect_const_access; + + struct nine_shader_info *info; + + int16_t op_info_map[D3DSIO_BREAKP + 1]; +}; + +#define IS_VS (tx->processor == TGSI_PROCESSOR_VERTEX) +#define IS_PS (tx->processor == TGSI_PROCESSOR_FRAGMENT) + +static void +sm1_read_semantic(struct shader_translator *, struct sm1_semantic *); + +static void +sm1_instruction_check(const struct sm1_instruction *insn) +{ + if (insn->opcode == D3DSIO_CRS) + { + if (insn->dst[0].mask & NINED3DSP_WRITEMASK_3) + { + DBG("CRS.mask.w\n"); + } + } +} + +static boolean +tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + INT i; + assert(index >= 0 && index < (NINE_MAX_CONST_F * 2)); + for (i = 0; i < tx->num_lconstf; ++i) { + if (tx->lconstf[i].idx == index) { + *src = tx->lconstf[i].reg; + return TRUE; + } + } + return FALSE; +} +static boolean +tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + assert(index >= 0 && index < NINE_MAX_CONST_I); + if (tx->lconsti[index].idx == index) + *src = tx->lconsti[index].reg; + return tx->lconsti[index].idx == index; +} +static boolean +tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index) +{ + assert(index >= 0 && index < NINE_MAX_CONST_B); + if (tx->lconstb[index].idx == index) + *src = tx->lconstb[index].reg; + return tx->lconstb[index].idx == index; +} + +static void +tx_set_lconstf(struct shader_translator *tx, INT index, float f[4]) +{ + unsigned n; + + /* Anno1404 sets out of range constants. */ + assert(index >= 0 && index < (NINE_MAX_CONST_F * 2)); + if (index >= NINE_MAX_CONST_F) + WARN("lconstf index %i too high, indirect access won't work\n", index); + + for (n = 0; n < tx->num_lconstf; ++n) + if (tx->lconstf[n].idx == index) + break; + if (n == tx->num_lconstf) { + if ((n % 8) == 0) { + tx->lconstf = REALLOC(tx->lconstf, + (n + 0) * sizeof(tx->lconstf[0]), + (n + 8) * sizeof(tx->lconstf[0])); + assert(tx->lconstf); + } + tx->num_lconstf++; + } + tx->lconstf[n].idx = index; + tx->lconstf[n].reg = ureg_imm4f(tx->ureg, f[0], f[1], f[2], f[3]); + + memcpy(tx->lconstf[n].imm.f, f, sizeof(tx->lconstf[n].imm.f)); +} +static void +tx_set_lconsti(struct shader_translator *tx, INT index, int i[4]) +{ + assert(index >= 0 && index < NINE_MAX_CONST_I); + tx->lconsti[index].idx = index; + tx->lconsti[index].reg = tx->native_integers ? + ureg_imm4i(tx->ureg, i[0], i[1], i[2], i[3]) : + ureg_imm4f(tx->ureg, i[0], i[1], i[2], i[3]); +} +static void +tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b) +{ + assert(index >= 0 && index < NINE_MAX_CONST_B); + tx->lconstb[index].idx = index; + tx->lconstb[index].reg = tx->native_integers ? + ureg_imm1u(tx->ureg, b ? 0xffffffff : 0) : + ureg_imm1f(tx->ureg, b ? 1.0f : 0.0f); +} + +static INLINE struct ureg_dst +tx_scratch(struct shader_translator *tx) +{ + assert(tx->num_scratch < Elements(tx->regs.t)); + if (ureg_dst_is_undef(tx->regs.t[tx->num_scratch])) + tx->regs.t[tx->num_scratch] = ureg_DECL_local_temporary(tx->ureg); + return tx->regs.t[tx->num_scratch++]; +} + +static INLINE struct ureg_dst +tx_scratch_scalar(struct shader_translator *tx) +{ + return ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X); +} + +static INLINE struct ureg_src +tx_src_scalar(struct ureg_dst dst) +{ + struct ureg_src src = ureg_src(dst); + int c = ffs(dst.WriteMask) - 1; + if (dst.WriteMask == (1 << c)) + src = ureg_scalar(src, c); + return src; +} + +/* Need to declare all constants if indirect addressing is used, + * otherwise we could scan the shader to determine the maximum. + * TODO: It doesn't really matter for nv50 so I won't do the scan, + * but radeon drivers might care, if they don't infer it from TGSI. + */ +static void +tx_decl_constants(struct shader_translator *tx) +{ + unsigned i, n = 0; + + for (i = 0; i < NINE_MAX_CONST_F; ++i) + ureg_DECL_constant(tx->ureg, n++); + for (i = 0; i < NINE_MAX_CONST_I; ++i) + ureg_DECL_constant(tx->ureg, n++); + for (i = 0; i < (NINE_MAX_CONST_B / 4); ++i) + ureg_DECL_constant(tx->ureg, n++); +} + +static INLINE void +tx_temp_alloc(struct shader_translator *tx, INT idx) +{ + assert(idx >= 0); + if (idx >= tx->num_temp) { + unsigned k = tx->num_temp; + unsigned n = idx + 1; + tx->regs.r = REALLOC(tx->regs.r, + k * sizeof(tx->regs.r[0]), + n * sizeof(tx->regs.r[0])); + for (; k < n; ++k) + tx->regs.r[k] = ureg_dst_undef(); + tx->num_temp = n; + } + if (ureg_dst_is_undef(tx->regs.r[idx])) + tx->regs.r[idx] = ureg_DECL_temporary(tx->ureg); +} + +static INLINE void +tx_addr_alloc(struct shader_translator *tx, INT idx) +{ + assert(idx == 0); + if (ureg_dst_is_undef(tx->regs.a)) + tx->regs.a = ureg_DECL_address(tx->ureg); +} + +static INLINE void +tx_pred_alloc(struct shader_translator *tx, INT idx) +{ + assert(idx == 0); + if (ureg_dst_is_undef(tx->regs.p)) + tx->regs.p = ureg_DECL_predicate(tx->ureg); +} + +static INLINE void +tx_texcoord_alloc(struct shader_translator *tx, INT idx) +{ + assert(IS_PS); + assert(idx >= 0 && idx < Elements(tx->regs.vT)); + if (ureg_src_is_undef(tx->regs.vT[idx])) + tx->regs.vT[idx] = ureg_DECL_fs_input(tx->ureg, tx->texcoord_sn, idx, + TGSI_INTERPOLATE_PERSPECTIVE); +} + +static INLINE unsigned * +tx_bgnloop(struct shader_translator *tx) +{ + tx->loop_depth++; + if (tx->loop_depth_max < tx->loop_depth) + tx->loop_depth_max = tx->loop_depth; + assert(tx->loop_depth < NINE_MAX_LOOP_DEPTH); + return &tx->loop_labels[tx->loop_depth - 1]; +} + +static INLINE unsigned * +tx_endloop(struct shader_translator *tx) +{ + assert(tx->loop_depth); + tx->loop_depth--; + ureg_fixup_label(tx->ureg, tx->loop_labels[tx->loop_depth], + ureg_get_instruction_number(tx->ureg)); + return &tx->loop_labels[tx->loop_depth]; +} + +static struct ureg_dst +tx_get_loopctr(struct shader_translator *tx) +{ + const unsigned l = tx->loop_depth - 1; + + if (!tx->loop_depth) + { + DBG("loop counter requested outside of loop\n"); + return ureg_dst_undef(); + } + + if (ureg_dst_is_undef(tx->regs.aL[l])) + { + struct ureg_dst rreg = ureg_DECL_local_temporary(tx->ureg); + struct ureg_dst areg = ureg_DECL_address(tx->ureg); + unsigned c; + + assert(l % 4 == 0); + for (c = l; c < (l + 4) && c < Elements(tx->regs.aL); ++c) { + tx->regs.rL[c] = ureg_writemask(rreg, 1 << (c & 3)); + tx->regs.aL[c] = ureg_writemask(areg, 1 << (c & 3)); + } + } + return tx->regs.rL[l]; +} +static struct ureg_dst +tx_get_aL(struct shader_translator *tx) +{ + if (!ureg_dst_is_undef(tx_get_loopctr(tx))) + return tx->regs.aL[tx->loop_depth - 1]; + return ureg_dst_undef(); +} + +static INLINE unsigned * +tx_cond(struct shader_translator *tx) +{ + assert(tx->cond_depth <= NINE_MAX_COND_DEPTH); + tx->cond_depth++; + return &tx->cond_labels[tx->cond_depth - 1]; +} + +static INLINE unsigned * +tx_elsecond(struct shader_translator *tx) +{ + assert(tx->cond_depth); + return &tx->cond_labels[tx->cond_depth - 1]; +} + +static INLINE void +tx_endcond(struct shader_translator *tx) +{ + assert(tx->cond_depth); + tx->cond_depth--; + ureg_fixup_label(tx->ureg, tx->cond_labels[tx->cond_depth], + ureg_get_instruction_number(tx->ureg)); +} + +static INLINE struct ureg_dst +nine_ureg_dst_register(unsigned file, int index) +{ + return ureg_dst(ureg_src_register(file, index)); +} + +static struct ureg_src +tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_src src; + struct ureg_dst tmp; + + switch (param->file) + { + case D3DSPR_TEMP: + assert(!param->rel); + tx_temp_alloc(tx, param->idx); + src = ureg_src(tx->regs.r[param->idx]); + break; + /* case D3DSPR_TEXTURE: == D3DSPR_ADDR */ + case D3DSPR_ADDR: + assert(!param->rel); + if (IS_VS) { + tx_addr_alloc(tx, param->idx); + src = ureg_src(tx->regs.a); + } else { + if (tx->version.major < 2 && tx->version.minor < 4) { + /* no subroutines, so should be defined */ + src = ureg_src(tx->regs.tS[param->idx]); + } else { + tx_texcoord_alloc(tx, param->idx); + src = tx->regs.vT[param->idx]; + } + } + break; + case D3DSPR_INPUT: + if (IS_VS) { + src = ureg_src_register(TGSI_FILE_INPUT, param->idx); + } else { + if (tx->version.major < 3) { + assert(!param->rel); + src = ureg_DECL_fs_input(tx->ureg, TGSI_SEMANTIC_COLOR, + param->idx, + TGSI_INTERPOLATE_PERSPECTIVE); + } else { + assert(!param->rel); /* TODO */ + assert(param->idx < Elements(tx->regs.v)); + src = tx->regs.v[param->idx]; + } + } + break; + case D3DSPR_PREDICATE: + assert(!param->rel); + tx_pred_alloc(tx, param->idx); + src = ureg_src(tx->regs.p); + break; + case D3DSPR_SAMPLER: + assert(param->mod == NINED3DSPSM_NONE); + assert(param->swizzle == NINED3DSP_NOSWIZZLE); + assert(!param->rel); + src = ureg_src_register(TGSI_FILE_SAMPLER, param->idx); + break; + case D3DSPR_CONST: + if (param->rel) + tx->indirect_const_access = TRUE; + if (param->rel || !tx_lconstf(tx, &src, param->idx)) { + if (!param->rel) + nine_info_mark_const_f_used(tx->info, param->idx); + src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx); + } + break; + case D3DSPR_CONST2: + case D3DSPR_CONST3: + case D3DSPR_CONST4: + DBG("CONST2/3/4 should have been collapsed into D3DSPR_CONST !\n"); + assert(!"CONST2/3/4"); + src = ureg_imm1f(ureg, 0.0f); + break; + case D3DSPR_CONSTINT: + if (param->rel || !tx_lconsti(tx, &src, param->idx)) { + if (!param->rel) + nine_info_mark_const_i_used(tx->info, param->idx); + src = ureg_src_register(TGSI_FILE_CONSTANT, + tx->info->const_i_base + param->idx); + } + break; + case D3DSPR_CONSTBOOL: + if (param->rel || !tx_lconstb(tx, &src, param->idx)) { + char r = param->idx / 4; + char s = param->idx & 3; + if (!param->rel) + nine_info_mark_const_b_used(tx->info, param->idx); + src = ureg_src_register(TGSI_FILE_CONSTANT, + tx->info->const_b_base + r); + src = ureg_swizzle(src, s, s, s, s); + } + break; + case D3DSPR_LOOP: + src = tx_src_scalar(tx_get_aL(tx)); + break; + case D3DSPR_MISCTYPE: + switch (param->idx) { + case D3DSMO_POSITION: + if (ureg_src_is_undef(tx->regs.vPos)) + tx->regs.vPos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, 0, + TGSI_INTERPOLATE_LINEAR); + if (tx->shift_wpos) { + /* TODO: do this only once */ + struct ureg_dst wpos = tx_scratch(tx); + ureg_SUB(ureg, wpos, tx->regs.vPos, + ureg_imm4f(ureg, 0.5f, 0.5f, 0.0f, 0.0f)); + src = ureg_src(wpos); + } else { + src = tx->regs.vPos; + } + break; + case D3DSMO_FACE: + if (ureg_src_is_undef(tx->regs.vFace)) { + tx->regs.vFace = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_FACE, 0, + TGSI_INTERPOLATE_CONSTANT); + tx->regs.vFace = ureg_scalar(tx->regs.vFace, TGSI_SWIZZLE_X); + } + src = tx->regs.vFace; + break; + default: + assert(!"invalid src D3DSMO"); + break; + } + assert(!param->rel); + break; + case D3DSPR_TEMPFLOAT16: + break; + default: + assert(!"invalid src D3DSPR"); + } + if (param->rel) + src = ureg_src_indirect(src, tx_src_param(tx, param->rel)); + + if (param->swizzle != NINED3DSP_NOSWIZZLE) + src = ureg_swizzle(src, + (param->swizzle >> 0) & 0x3, + (param->swizzle >> 2) & 0x3, + (param->swizzle >> 4) & 0x3, + (param->swizzle >> 6) & 0x3); + + switch (param->mod) { + case NINED3DSPSM_ABS: + src = ureg_abs(src); + break; + case NINED3DSPSM_ABSNEG: + src = ureg_negate(ureg_abs(src)); + break; + case NINED3DSPSM_NEG: + src = ureg_negate(src); + break; + case NINED3DSPSM_BIAS: + tmp = tx_scratch(tx); + ureg_SUB(ureg, tmp, src, ureg_imm1f(ureg, 0.5f)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_BIASNEG: + tmp = tx_scratch(tx); + ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 0.5f), src); + src = ureg_src(tmp); + break; + case NINED3DSPSM_NOT: + if (tx->native_integers) { + tmp = tx_scratch(tx); + ureg_NOT(ureg, tmp, src); + src = ureg_src(tmp); + break; + } + /* fall through */ + case NINED3DSPSM_COMP: + tmp = tx_scratch(tx); + ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), src); + src = ureg_src(tmp); + break; + case NINED3DSPSM_DZ: + case NINED3DSPSM_DW: + /* handled in instruction */ + break; + case NINED3DSPSM_SIGN: + tmp = tx_scratch(tx); + ureg_MAD(ureg, tmp, src, ureg_imm1f(ureg, 2.0f), ureg_imm1f(ureg, -1.0f)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_SIGNNEG: + tmp = tx_scratch(tx); + ureg_MAD(ureg, tmp, src, ureg_imm1f(ureg, -2.0f), ureg_imm1f(ureg, 1.0f)); + src = ureg_src(tmp); + break; + case NINED3DSPSM_X2: + tmp = tx_scratch(tx); + ureg_ADD(ureg, tmp, src, src); + src = ureg_src(tmp); + break; + case NINED3DSPSM_X2NEG: + tmp = tx_scratch(tx); + ureg_ADD(ureg, tmp, src, src); + src = ureg_negate(ureg_src(tmp)); + break; + default: + assert(param->mod == NINED3DSPSM_NONE); + break; + } + + return src; +} + +static struct ureg_dst +_tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param) +{ + struct ureg_dst dst; + + switch (param->file) + { + case D3DSPR_TEMP: + assert(!param->rel); + tx_temp_alloc(tx, param->idx); + dst = tx->regs.r[param->idx]; + break; + /* case D3DSPR_TEXTURE: == D3DSPR_ADDR */ + case D3DSPR_ADDR: + assert(!param->rel); + if (tx->version.major < 2 && !IS_VS) { + if (ureg_dst_is_undef(tx->regs.tS[param->idx])) + tx->regs.tS[param->idx] = ureg_DECL_temporary(tx->ureg); + dst = tx->regs.tS[param->idx]; + } else + if (!IS_VS && tx->insn.opcode == D3DSIO_TEXKILL) { /* maybe others, too */ + tx_texcoord_alloc(tx, param->idx); + dst = ureg_dst(tx->regs.vT[param->idx]); + } else { + tx_addr_alloc(tx, param->idx); + dst = tx->regs.a; + } + break; + case D3DSPR_RASTOUT: + assert(!param->rel); + switch (param->idx) { + case 0: + if (ureg_dst_is_undef(tx->regs.oPos)) + tx->regs.oPos = + ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_POSITION, 0); + dst = tx->regs.oPos; + break; + case 1: + if (ureg_dst_is_undef(tx->regs.oFog)) + tx->regs.oFog = + ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_FOG, 0); + dst = tx->regs.oFog; + break; + case 2: + if (ureg_dst_is_undef(tx->regs.oPts)) + tx->regs.oPts = + ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0); + dst = tx->regs.oPts; + break; + default: + assert(0); + break; + } + break; + /* case D3DSPR_TEXCRDOUT: == D3DSPR_OUTPUT */ + case D3DSPR_OUTPUT: + if (tx->version.major < 3) { + assert(!param->rel); + dst = ureg_DECL_output(tx->ureg, tx->texcoord_sn, param->idx); + } else { + assert(!param->rel); /* TODO */ + assert(param->idx < Elements(tx->regs.o)); + dst = tx->regs.o[param->idx]; + } + break; + case D3DSPR_ATTROUT: /* VS */ + case D3DSPR_COLOROUT: /* PS */ + assert(param->idx >= 0 && param->idx < 4); + assert(!param->rel); + tx->info->rt_mask |= 1 << param->idx; + if (ureg_dst_is_undef(tx->regs.oCol[param->idx])) + tx->regs.oCol[param->idx] = + ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx); + dst = tx->regs.oCol[param->idx]; + if (IS_VS && tx->version.major < 3) + dst = ureg_saturate(dst); + break; + case D3DSPR_DEPTHOUT: + assert(!param->rel); + if (ureg_dst_is_undef(tx->regs.oDepth)) + tx->regs.oDepth = + ureg_DECL_output_masked(tx->ureg, TGSI_SEMANTIC_POSITION, 0, + TGSI_WRITEMASK_Z); + dst = tx->regs.oDepth; /* XXX: must write .z component */ + break; + case D3DSPR_PREDICATE: + assert(!param->rel); + tx_pred_alloc(tx, param->idx); + dst = tx->regs.p; + break; + case D3DSPR_TEMPFLOAT16: + DBG("unhandled D3DSPR: %u\n", param->file); + break; + default: + assert(!"invalid dst D3DSPR"); + break; + } + if (param->rel) + dst = ureg_dst_indirect(dst, tx_src_param(tx, param->rel)); + + if (param->mask != NINED3DSP_WRITEMASK_ALL) + dst = ureg_writemask(dst, param->mask); + if (param->mod & NINED3DSPDM_SATURATE) + dst = ureg_saturate(dst); + + return dst; +} + +static struct ureg_dst +tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param) +{ + if (param->shift) { + tx->regs.tdst = ureg_writemask(tx_scratch(tx), param->mask); + return tx->regs.tdst; + } + return _tx_dst_param(tx, param); +} + +static void +tx_apply_dst0_modifiers(struct shader_translator *tx) +{ + struct ureg_dst rdst; + float f; + + if (!tx->insn.ndst || !tx->insn.dst[0].shift || tx->insn.opcode == D3DSIO_TEXKILL) + return; + rdst = _tx_dst_param(tx, &tx->insn.dst[0]); + + assert(rdst.File != TGSI_FILE_ADDRESS); /* this probably isn't possible */ + + if (tx->insn.dst[0].shift < 0) + f = 1.0f / (1 << -tx->insn.dst[0].shift); + else + f = 1 << tx->insn.dst[0].shift; + + ureg_MUL(tx->ureg, rdst, ureg_src(tx->regs.tdst), ureg_imm1f(tx->ureg, f)); +} + +static struct ureg_src +tx_dst_param_as_src(struct shader_translator *tx, const struct sm1_dst_param *param) +{ + struct ureg_src src; + + assert(!param->shift); + assert(!(param->mod & NINED3DSPDM_SATURATE)); + + switch (param->file) { + case D3DSPR_INPUT: + if (IS_VS) { + src = ureg_src_register(TGSI_FILE_INPUT, param->idx); + } else { + assert(!param->rel); + assert(param->idx < Elements(tx->regs.v)); + src = tx->regs.v[param->idx]; + } + break; + default: + src = ureg_src(tx_dst_param(tx, param)); + break; + } + if (param->rel) + src = ureg_src_indirect(src, tx_src_param(tx, param->rel)); + + if (!param->mask) + WARN("mask is 0, using identity swizzle\n"); + + if (param->mask && param->mask != NINED3DSP_WRITEMASK_ALL) { + char s[4]; + int n; + int c; + for (n = 0, c = 0; c < 4; ++c) + if (param->mask & (1 << c)) + s[n++] = c; + assert(n); + for (c = n; c < 4; ++c) + s[c] = s[n - 1]; + src = ureg_swizzle(src, s[0], s[1], s[2], s[3]); + } + return src; +} + +static HRESULT +NineTranslateInstruction_Mkxn(struct shader_translator *tx, const unsigned k, const unsigned n) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst; + struct ureg_src src[2]; + unsigned i; + + dst = tx_dst_param(tx, &tx->insn.dst[0]); + src[0] = tx_src_param(tx, &tx->insn.src[0]); + src[1] = tx_src_param(tx, &tx->insn.src[1]); + + for (i = 0; i < n; i++, src[1].Index++) + { + const unsigned m = (1 << i); + + if (!(dst.WriteMask & m)) + continue; + + /* XXX: src == dst case ? */ + + switch (k) { + case 3: + ureg_DP3(ureg, ureg_writemask(dst, m), src[0], src[1]); + break; + case 4: + ureg_DP4(ureg, ureg_writemask(dst, m), src[0], src[1]); + break; + default: + DBG("invalid operation: M%ux%u\n", m, n); + break; + } + } + + return D3D_OK; +} + +#define VNOTSUPPORTED 0, 0 +#define V(maj, min) (((maj) << 8) | (min)) + +static INLINE const char * +d3dsio_to_string( unsigned opcode ) +{ + static const char *names[] = { + "NOP", + "MOV", + "ADD", + "SUB", + "MAD", + "MUL", + "RCP", + "RSQ", + "DP3", + "DP4", + "MIN", + "MAX", + "SLT", + "SGE", + "EXP", + "LOG", + "LIT", + "DST", + "LRP", + "FRC", + "M4x4", + "M4x3", + "M3x4", + "M3x3", + "M3x2", + "CALL", + "CALLNZ", + "LOOP", + "RET", + "ENDLOOP", + "LABEL", + "DCL", + "POW", + "CRS", + "SGN", + "ABS", + "NRM", + "SINCOS", + "REP", + "ENDREP", + "IF", + "IFC", + "ELSE", + "ENDIF", + "BREAK", + "BREAKC", + "MOVA", + "DEFB", + "DEFI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "TEXCOORD", + "TEXKILL", + "TEX", + "TEXBEM", + "TEXBEML", + "TEXREG2AR", + "TEXREG2GB", + "TEXM3x2PAD", + "TEXM3x2TEX", + "TEXM3x3PAD", + "TEXM3x3TEX", + NULL, + "TEXM3x3SPEC", + "TEXM3x3VSPEC", + "EXPP", + "LOGP", + "CND", + "DEF", + "TEXREG2RGB", + "TEXDP3TEX", + "TEXM3x2DEPTH", + "TEXDP3", + "TEXM3x3", + "TEXDEPTH", + "CMP", + "BEM", + "DP2ADD", + "DSX", + "DSY", + "TEXLDD", + "SETP", + "TEXLDL", + "BREAKP" + }; + + if (opcode < Elements(names)) return names[opcode]; + + switch (opcode) { + case D3DSIO_PHASE: return "PHASE"; + case D3DSIO_COMMENT: return "COMMENT"; + case D3DSIO_END: return "END"; + default: + return NULL; + } +} + +#define NULL_INSTRUCTION { 0, { 0, 0 }, { 0, 0 }, 0, 0, NULL } +#define IS_VALID_INSTRUCTION(inst) ((inst).vert_version.min | \ + (inst).vert_version.max | \ + (inst).frag_version.min | \ + (inst).frag_version.max) + +#define SPECIAL(name) \ + NineTranslateInstruction_##name + +#define DECL_SPECIAL(name) \ + static HRESULT \ + NineTranslateInstruction_##name( struct shader_translator *tx ) + +static HRESULT +NineTranslateInstruction_Generic(struct shader_translator *); + +DECL_SPECIAL(M4x4) +{ + return NineTranslateInstruction_Mkxn(tx, 4, 3); +} + +DECL_SPECIAL(M4x3) +{ + return NineTranslateInstruction_Mkxn(tx, 4, 3); +} + +DECL_SPECIAL(M3x4) +{ + return NineTranslateInstruction_Mkxn(tx, 3, 4); +} + +DECL_SPECIAL(M3x3) +{ + return NineTranslateInstruction_Mkxn(tx, 3, 3); +} + +DECL_SPECIAL(M3x2) +{ + return NineTranslateInstruction_Mkxn(tx, 3, 2); +} + +DECL_SPECIAL(CMP) +{ + ureg_CMP(tx->ureg, tx_dst_param(tx, &tx->insn.dst[0]), + tx_src_param(tx, &tx->insn.src[0]), + tx_src_param(tx, &tx->insn.src[2]), + tx_src_param(tx, &tx->insn.src[1])); + return D3D_OK; +} + +DECL_SPECIAL(CND) +{ + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_dst cgt; + struct ureg_src cnd; + + if (tx->insn.coissue && tx->version.major == 1 && tx->version.minor < 4) { + ureg_MOV(tx->ureg, + dst, tx_src_param(tx, &tx->insn.src[1])); + return D3D_OK; + } + + cnd = tx_src_param(tx, &tx->insn.src[0]); +#ifdef NINE_TGSI_LAZY_R600 + cgt = tx_scratch(tx); + + if (tx->version.major == 1 && tx->version.minor < 4) { + cgt.WriteMask = TGSI_WRITEMASK_W; + ureg_SGT(tx->ureg, cgt, cnd, ureg_imm1f(tx->ureg, 0.5f)); + cnd = ureg_scalar(cnd, TGSI_SWIZZLE_W); + } else { + ureg_SGT(tx->ureg, cgt, cnd, ureg_imm1f(tx->ureg, 0.5f)); + } + ureg_CMP(tx->ureg, dst, + tx_src_param(tx, &tx->insn.src[1]), + tx_src_param(tx, &tx->insn.src[2]), ureg_negate(cnd)); +#else + if (tx->version.major == 1 && tx->version.minor < 4) + cnd = ureg_scalar(cnd, TGSI_SWIZZLE_W); + ureg_CND(tx->ureg, dst, + tx_src_param(tx, &tx->insn.src[1]), + tx_src_param(tx, &tx->insn.src[2]), cnd); +#endif + return D3D_OK; +} + +DECL_SPECIAL(CALL) +{ + assert(tx->insn.src[0].idx < tx->num_inst_labels); + ureg_CAL(tx->ureg, &tx->inst_labels[tx->insn.src[0].idx]); + return D3D_OK; +} + +DECL_SPECIAL(CALLNZ) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst tmp = tx_scratch_scalar(tx); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[1]); + + /* NOTE: source should be const bool, so we can use NOT/SUB instead of [U]SNE 0 */ + if (!tx->insn.flags) { + if (tx->native_integers) + ureg_NOT(ureg, tmp, src); + else + ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), src); + } + ureg_IF(ureg, tx->insn.flags ? src : tx_src_scalar(tmp), tx_cond(tx)); + ureg_CAL(ureg, &tx->inst_labels[tx->insn.src[0].idx]); + tx_endcond(tx); + ureg_ENDIF(ureg); + return D3D_OK; +} + +DECL_SPECIAL(MOV_vs1x) +{ + if (tx->insn.dst[0].file == D3DSPR_ADDR) { + ureg_ARL(tx->ureg, + tx_dst_param(tx, &tx->insn.dst[0]), + tx_src_param(tx, &tx->insn.src[0])); + return D3D_OK; + } + return NineTranslateInstruction_Generic(tx); +} + +DECL_SPECIAL(LOOP) +{ + struct ureg_program *ureg = tx->ureg; + unsigned *label; + struct ureg_src src = tx_src_param(tx, &tx->insn.src[1]); + struct ureg_src iter = ureg_scalar(src, TGSI_SWIZZLE_X); + struct ureg_src init = ureg_scalar(src, TGSI_SWIZZLE_Y); + struct ureg_src step = ureg_scalar(src, TGSI_SWIZZLE_Z); + struct ureg_dst ctr; + struct ureg_dst tmp = tx_scratch_scalar(tx); + + label = tx_bgnloop(tx); + ctr = tx_get_loopctr(tx); + + ureg_MOV(tx->ureg, ctr, init); + ureg_BGNLOOP(tx->ureg, label); + if (tx->native_integers) { + /* we'll let the backend pull up that MAD ... */ + ureg_UMAD(ureg, tmp, iter, step, init); + ureg_USEQ(ureg, tmp, ureg_src(ctr), tx_src_scalar(tmp)); +#ifdef NINE_TGSI_LAZY_DEVS + ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx)); +#endif + } else { + /* can't simply use SGE for precision because step might be negative */ + ureg_MAD(ureg, tmp, iter, step, init); + ureg_SEQ(ureg, tmp, ureg_src(ctr), tx_src_scalar(tmp)); +#ifdef NINE_TGSI_LAZY_DEVS + ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx)); +#endif + } +#ifdef NINE_TGSI_LAZY_DEVS + ureg_BRK(ureg); + tx_endcond(tx); + ureg_ENDIF(ureg); +#else + ureg_BREAKC(ureg, tx_src_scalar(tmp)); +#endif + if (tx->native_integers) { + ureg_UARL(ureg, tx_get_aL(tx), tx_src_scalar(ctr)); + ureg_UADD(ureg, ctr, tx_src_scalar(ctr), step); + } else { + ureg_ARL(ureg, tx_get_aL(tx), tx_src_scalar(ctr)); + ureg_ADD(ureg, ctr, tx_src_scalar(ctr), step); + } + return D3D_OK; +} + +DECL_SPECIAL(RET) +{ + ureg_RET(tx->ureg); + return D3D_OK; +} + +DECL_SPECIAL(ENDLOOP) +{ + ureg_ENDLOOP(tx->ureg, tx_endloop(tx)); + return D3D_OK; +} + +DECL_SPECIAL(LABEL) +{ + unsigned k = tx->num_inst_labels; + unsigned n = tx->insn.src[0].idx; + assert(n < 2048); + if (n >= k) + tx->inst_labels = REALLOC(tx->inst_labels, + k * sizeof(tx->inst_labels[0]), + n * sizeof(tx->inst_labels[0])); + + tx->inst_labels[n] = ureg_get_instruction_number(tx->ureg); + return D3D_OK; +} + +DECL_SPECIAL(SINCOS) +{ + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + + assert(!(dst.WriteMask & 0xc)); + + dst.WriteMask &= TGSI_WRITEMASK_XY; /* z undefined, w untouched */ + ureg_SCS(tx->ureg, dst, src); + return D3D_OK; +} + +DECL_SPECIAL(SGN) +{ + ureg_SSG(tx->ureg, + tx_dst_param(tx, &tx->insn.dst[0]), + tx_src_param(tx, &tx->insn.src[0])); + return D3D_OK; +} + +DECL_SPECIAL(REP) +{ + struct ureg_program *ureg = tx->ureg; + unsigned *label; + struct ureg_src rep = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_dst ctr; + struct ureg_dst tmp = tx_scratch_scalar(tx); + struct ureg_src imm = + tx->native_integers ? ureg_imm1u(ureg, 0) : ureg_imm1f(ureg, 0.0f); + + label = tx_bgnloop(tx); + ctr = tx_get_loopctr(tx); + + /* NOTE: rep must be constant, so we don't have to save the count */ + assert(rep.File == TGSI_FILE_CONSTANT || rep.File == TGSI_FILE_IMMEDIATE); + + ureg_MOV(ureg, ctr, imm); + ureg_BGNLOOP(ureg, label); + if (tx->native_integers) + { + ureg_USGE(ureg, tmp, tx_src_scalar(ctr), rep); +#ifdef NINE_TGSI_LAZY_DEVS + ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx)); +#endif + } + else + { + ureg_SGE(ureg, tmp, tx_src_scalar(ctr), rep); +#ifdef NINE_TGSI_LAZY_DEVS + ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx)); +#endif + } +#ifdef NINE_TGSI_LAZY_DEVS + ureg_BRK(ureg); + tx_endcond(tx); + ureg_ENDIF(ureg); +#else + ureg_BREAKC(ureg, tx_src_scalar(tmp)); +#endif + + if (tx->native_integers) { + ureg_UADD(ureg, ctr, tx_src_scalar(ctr), ureg_imm1u(ureg, 1)); + } else { + ureg_ADD(ureg, ctr, tx_src_scalar(ctr), ureg_imm1f(ureg, 1.0f)); + } + + return D3D_OK; +} + +DECL_SPECIAL(ENDREP) +{ + ureg_ENDLOOP(tx->ureg, tx_endloop(tx)); + return D3D_OK; +} + +DECL_SPECIAL(ENDIF) +{ + tx_endcond(tx); + ureg_ENDIF(tx->ureg); + return D3D_OK; +} + +DECL_SPECIAL(IF) +{ + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + + if (tx->native_integers && tx->insn.src[0].file == D3DSPR_CONSTBOOL) + ureg_UIF(tx->ureg, src, tx_cond(tx)); + else + ureg_IF(tx->ureg, src, tx_cond(tx)); + + return D3D_OK; +} + +static INLINE unsigned +sm1_insn_flags_to_tgsi_setop(BYTE flags) +{ + switch (flags) { + case NINED3DSHADER_REL_OP_GT: return TGSI_OPCODE_SGT; + case NINED3DSHADER_REL_OP_EQ: return TGSI_OPCODE_SEQ; + case NINED3DSHADER_REL_OP_GE: return TGSI_OPCODE_SGE; + case NINED3DSHADER_REL_OP_LT: return TGSI_OPCODE_SLT; + case NINED3DSHADER_REL_OP_NE: return TGSI_OPCODE_SNE; + case NINED3DSHADER_REL_OP_LE: return TGSI_OPCODE_SLE; + default: + assert(!"invalid comparison flags"); + return TGSI_OPCODE_SFL; + } +} + +DECL_SPECIAL(IFC) +{ + const unsigned cmp_op = sm1_insn_flags_to_tgsi_setop(tx->insn.flags); + struct ureg_src src[2]; + struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X); + src[0] = tx_src_param(tx, &tx->insn.src[0]); + src[1] = tx_src_param(tx, &tx->insn.src[1]); + ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2); + ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx)); + return D3D_OK; +} + +DECL_SPECIAL(ELSE) +{ + ureg_ELSE(tx->ureg, tx_elsecond(tx)); + return D3D_OK; +} + +DECL_SPECIAL(BREAKC) +{ + const unsigned cmp_op = sm1_insn_flags_to_tgsi_setop(tx->insn.flags); + struct ureg_src src[2]; + struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X); + src[0] = tx_src_param(tx, &tx->insn.src[0]); + src[1] = tx_src_param(tx, &tx->insn.src[1]); + ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2); +#ifdef NINE_TGSI_LAZY_DEVS + ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx)); + ureg_BRK(tx->ureg); + tx_endcond(tx); + ureg_ENDIF(tx->ureg); +#else + ureg_BREAKC(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X)); +#endif + return D3D_OK; +} + +static const char *sm1_declusage_names[] = +{ + [D3DDECLUSAGE_POSITION] = "POSITION", + [D3DDECLUSAGE_BLENDWEIGHT] = "BLENDWEIGHT", + [D3DDECLUSAGE_BLENDINDICES] = "BLENDINDICES", + [D3DDECLUSAGE_NORMAL] = "NORMAL", + [D3DDECLUSAGE_PSIZE] = "PSIZE", + [D3DDECLUSAGE_TEXCOORD] = "TEXCOORD", + [D3DDECLUSAGE_TANGENT] = "TANGENT", + [D3DDECLUSAGE_BINORMAL] = "BINORMAL", + [D3DDECLUSAGE_TESSFACTOR] = "TESSFACTOR", + [D3DDECLUSAGE_POSITIONT] = "POSITIONT", + [D3DDECLUSAGE_COLOR] = "COLOR", + [D3DDECLUSAGE_FOG] = "FOG", + [D3DDECLUSAGE_DEPTH] = "DEPTH", + [D3DDECLUSAGE_SAMPLE] = "SAMPLE" +}; + +static INLINE unsigned +sm1_to_nine_declusage(struct sm1_semantic *dcl) +{ + return nine_d3d9_to_nine_declusage(dcl->usage, dcl->usage_idx); +} + +static void +sm1_declusage_to_tgsi(struct tgsi_declaration_semantic *sem, + boolean tc, + struct sm1_semantic *dcl) +{ + const unsigned generic_base = tc ? 0 : 8; /* TEXCOORD[0..7] */ + + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = 0; + + /* TGSI_SEMANTIC_GENERIC assignments (+8 if !PIPE_CAP_TGSI_TEXCOORD): + * Try to put frequently used semantics at low GENERIC indices. + * + * POSITION[1..4]: 17, 27, 28, 29 + * COLOR[2..4]: 14, 15, 26 + * TEXCOORD[8..15]: 10, 11, 18, 19, 20, 21, 22, 23 + * BLENDWEIGHT[0..3]: 0, 4, 8, 12 + * BLENDINDICES[0..3]: 1, 5, 9, 13 + * NORMAL[0..1]: 2, 6 + * TANGENT[0]: 3, 24 + * BINORMAL[0]: 7, 25 + * TESSFACTOR[0]: 16 + */ + + switch (dcl->usage) { + case D3DDECLUSAGE_POSITION: + case D3DDECLUSAGE_POSITIONT: + case D3DDECLUSAGE_DEPTH: + sem->Name = TGSI_SEMANTIC_POSITION; + assert(dcl->usage_idx <= 4); + if (dcl->usage_idx == 1) { + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = generic_base + 17; + } else + if (dcl->usage_idx >= 2) { + sem->Name = TGSI_SEMANTIC_GENERIC; + sem->Index = generic_base + 27 + (dcl->usage_idx - 2); + } + break; + case D3DDECLUSAGE_COLOR: + assert(dcl->usage_idx <= 4); + if (dcl->usage_idx < 2) { + sem->Name = TGSI_SEMANTIC_COLOR; + sem->Index = dcl->usage_idx; + } else + if (dcl->usage_idx < 4) { + sem->Index = generic_base + 14 + (dcl->usage_idx - 2); + } else { + sem->Index = generic_base + 26; + } + break; + case D3DDECLUSAGE_FOG: + sem->Name = TGSI_SEMANTIC_FOG; + assert(dcl->usage_idx == 0); + break; + case D3DDECLUSAGE_PSIZE: + sem->Name = TGSI_SEMANTIC_PSIZE; + assert(dcl->usage_idx == 0); + break; + case D3DDECLUSAGE_TEXCOORD: + assert(dcl->usage_idx < 16); + if (dcl->usage_idx < 8) { + if (tc) + sem->Name = TGSI_SEMANTIC_TEXCOORD; + sem->Index = dcl->usage_idx; + } else + if (dcl->usage_idx < 10) { + sem->Index = generic_base + 10 + (dcl->usage_idx - 8); + } else { + sem->Index = generic_base + 18 + (dcl->usage_idx - 10); + } + break; + case D3DDECLUSAGE_BLENDWEIGHT: /* 0, 4, 8, 12 */ + assert(dcl->usage_idx < 4); + sem->Index = generic_base + dcl->usage_idx * 4; + break; + case D3DDECLUSAGE_BLENDINDICES: /* 1, 5, 9, 13 */ + assert(dcl->usage_idx < 4); + sem->Index = generic_base + dcl->usage_idx * 4 + 1; + break; + case D3DDECLUSAGE_NORMAL: /* 2, 3 */ + assert(dcl->usage_idx < 2); + sem->Index = generic_base + 2 + dcl->usage_idx * 4; + break; + case D3DDECLUSAGE_TANGENT: + /* Yes these are weird, but we try to fit the more frequently used + * into lower slots. */ + assert(dcl->usage_idx <= 1); + sem->Index = generic_base + (dcl->usage_idx ? 24 : 3); + break; + case D3DDECLUSAGE_BINORMAL: + assert(dcl->usage_idx <= 1); + sem->Index = generic_base + (dcl->usage_idx ? 25 : 7); + break; + case D3DDECLUSAGE_TESSFACTOR: + assert(dcl->usage_idx == 0); + sem->Index = generic_base + 16; + break; + case D3DDECLUSAGE_SAMPLE: + sem->Name = TGSI_SEMANTIC_COUNT; + break; + default: + assert(!"Invalid DECLUSAGE."); + break; + } +} + +#define NINED3DSTT_1D (D3DSTT_1D >> D3DSP_TEXTURETYPE_SHIFT) +#define NINED3DSTT_2D (D3DSTT_2D >> D3DSP_TEXTURETYPE_SHIFT) +#define NINED3DSTT_VOLUME (D3DSTT_VOLUME >> D3DSP_TEXTURETYPE_SHIFT) +#define NINED3DSTT_CUBE (D3DSTT_CUBE >> D3DSP_TEXTURETYPE_SHIFT) +static INLINE unsigned +d3dstt_to_tgsi_tex(BYTE sampler_type) +{ + switch (sampler_type) { + case NINED3DSTT_1D: return TGSI_TEXTURE_1D; + case NINED3DSTT_2D: return TGSI_TEXTURE_2D; + case NINED3DSTT_VOLUME: return TGSI_TEXTURE_3D; + case NINED3DSTT_CUBE: return TGSI_TEXTURE_CUBE; + default: + assert(0); + return TGSI_TEXTURE_UNKNOWN; + } +} +static INLINE unsigned +d3dstt_to_tgsi_tex_shadow(BYTE sampler_type) +{ + switch (sampler_type) { + case NINED3DSTT_1D: return TGSI_TEXTURE_SHADOW1D; + case NINED3DSTT_2D: return TGSI_TEXTURE_SHADOW2D; + case NINED3DSTT_VOLUME: + case NINED3DSTT_CUBE: + default: + assert(0); + return TGSI_TEXTURE_UNKNOWN; + } +} +static INLINE unsigned +ps1x_sampler_type(const struct nine_shader_info *info, unsigned stage) +{ + switch ((info->sampler_ps1xtypes >> (stage * 2)) & 0x3) { + case 1: return TGSI_TEXTURE_1D; + case 0: return TGSI_TEXTURE_2D; + case 3: return TGSI_TEXTURE_3D; + default: + return TGSI_TEXTURE_CUBE; + } +} + +static const char * +sm1_sampler_type_name(BYTE sampler_type) +{ + switch (sampler_type) { + case NINED3DSTT_1D: return "1D"; + case NINED3DSTT_2D: return "2D"; + case NINED3DSTT_VOLUME: return "VOLUME"; + case NINED3DSTT_CUBE: return "CUBE"; + default: + return "(D3DSTT_?)"; + } +} + +static INLINE unsigned +nine_tgsi_to_interp_mode(struct tgsi_declaration_semantic *sem) +{ + switch (sem->Name) { + case TGSI_SEMANTIC_POSITION: + case TGSI_SEMANTIC_NORMAL: + return TGSI_INTERPOLATE_LINEAR; + case TGSI_SEMANTIC_BCOLOR: + case TGSI_SEMANTIC_COLOR: + case TGSI_SEMANTIC_FOG: + case TGSI_SEMANTIC_GENERIC: + case TGSI_SEMANTIC_TEXCOORD: + case TGSI_SEMANTIC_CLIPDIST: + case TGSI_SEMANTIC_CLIPVERTEX: + return TGSI_INTERPOLATE_PERSPECTIVE; + case TGSI_SEMANTIC_EDGEFLAG: + case TGSI_SEMANTIC_FACE: + case TGSI_SEMANTIC_INSTANCEID: + case TGSI_SEMANTIC_PCOORD: + case TGSI_SEMANTIC_PRIMID: + case TGSI_SEMANTIC_PSIZE: + case TGSI_SEMANTIC_VERTEXID: + return TGSI_INTERPOLATE_CONSTANT; + default: + assert(0); + return TGSI_INTERPOLATE_CONSTANT; + } +} + +DECL_SPECIAL(DCL) +{ + struct ureg_program *ureg = tx->ureg; + boolean is_input; + boolean is_sampler; + struct tgsi_declaration_semantic tgsi; + struct sm1_semantic sem; + sm1_read_semantic(tx, &sem); + + is_input = sem.reg.file == D3DSPR_INPUT; + is_sampler = + sem.usage == D3DDECLUSAGE_SAMPLE || sem.reg.file == D3DSPR_SAMPLER; + + DUMP("DCL "); + sm1_dump_dst_param(&sem.reg); + if (is_sampler) + DUMP(" %s\n", sm1_sampler_type_name(sem.sampler_type)); + else + if (tx->version.major >= 3) + DUMP(" %s%i\n", sm1_declusage_names[sem.usage], sem.usage_idx); + else + if (sem.usage | sem.usage_idx) + DUMP(" %u[%u]\n", sem.usage, sem.usage_idx); + else + DUMP("\n"); + + if (is_sampler) { + const unsigned m = 1 << sem.reg.idx; + ureg_DECL_sampler(ureg, sem.reg.idx); + tx->info->sampler_mask |= m; + tx->sampler_targets[sem.reg.idx] = (tx->info->sampler_mask_shadow & m) ? + d3dstt_to_tgsi_tex_shadow(sem.sampler_type) : + d3dstt_to_tgsi_tex(sem.sampler_type); + return D3D_OK; + } + + sm1_declusage_to_tgsi(&tgsi, tx->want_texcoord, &sem); + if (IS_VS) { + if (is_input) { + /* linkage outside of shader with vertex declaration */ + ureg_DECL_vs_input(ureg, sem.reg.idx); + assert(sem.reg.idx < Elements(tx->info->input_map)); + tx->info->input_map[sem.reg.idx] = sm1_to_nine_declusage(&sem); + tx->info->num_inputs = sem.reg.idx + 1; + /* NOTE: preserving order in case of indirect access */ + } else + if (tx->version.major >= 3) { + /* SM2 output semantic determined by file */ + assert(sem.reg.mask != 0); + if (sem.usage == D3DDECLUSAGE_POSITIONT) + tx->info->position_t = TRUE; + assert(sem.reg.idx < Elements(tx->regs.o)); + tx->regs.o[sem.reg.idx] = ureg_DECL_output_masked( + ureg, tgsi.Name, tgsi.Index, sem.reg.mask); + + if (tgsi.Name == TGSI_SEMANTIC_PSIZE) + tx->regs.oPts = tx->regs.o[sem.reg.idx]; + } + } else { + if (is_input && tx->version.major >= 3) { + /* SM3 only, SM2 input semantic determined by file */ + assert(sem.reg.idx < Elements(tx->regs.v)); + tx->regs.v[sem.reg.idx] = ureg_DECL_fs_input_cyl_centroid( + ureg, tgsi.Name, tgsi.Index, + nine_tgsi_to_interp_mode(&tgsi), + 0, /* cylwrap */ + sem.reg.mod & NINED3DSPDM_CENTROID); + } else + if (!is_input && 0) { /* declare in COLOROUT/DEPTHOUT case */ + /* FragColor or FragDepth */ + assert(sem.reg.mask != 0); + ureg_DECL_output_masked(ureg, tgsi.Name, tgsi.Index, sem.reg.mask); + } + } + return D3D_OK; +} + +DECL_SPECIAL(DEF) +{ + tx_set_lconstf(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.f); + return D3D_OK; +} + +DECL_SPECIAL(DEFB) +{ + tx_set_lconstb(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.b); + return D3D_OK; +} + +DECL_SPECIAL(DEFI) +{ + tx_set_lconsti(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.i); + return D3D_OK; +} + +DECL_SPECIAL(NRM) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst tmp = tx_scratch_scalar(tx); + struct ureg_src nrm = tx_src_scalar(tmp); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + ureg_DP3(ureg, tmp, src, src); + ureg_RSQ(ureg, tmp, nrm); + ureg_MUL(ureg, tx_dst_param(tx, &tx->insn.dst[0]), src, nrm); + return D3D_OK; +} + +DECL_SPECIAL(DP2ADD) +{ +#ifdef NINE_TGSI_LAZY_R600 + struct ureg_dst tmp = tx_scratch_scalar(tx); + struct ureg_src dp2 = tx_src_scalar(tmp); + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[3]; + int i; + for (i = 0; i < 3; ++i) + src[i] = tx_src_param(tx, &tx->insn.src[i]); + assert_replicate_swizzle(&src[2]); + + ureg_DP2(tx->ureg, tmp, src[0], src[1]); + ureg_ADD(tx->ureg, dst, src[2], dp2); + + return D3D_OK; +#else + return NineTranslateInstruction_Generic(tx); +#endif +} + +DECL_SPECIAL(TEXCOORD) +{ + struct ureg_program *ureg = tx->ureg; + const unsigned s = tx->insn.dst[0].idx; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + + if (ureg_src_is_undef(tx->regs.vT[s])) + tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + ureg_MOV(ureg, dst, tx->regs.vT[s]); /* XXX is this sufficient ? */ + + return D3D_OK; +} + +DECL_SPECIAL(TEXCOORD_ps14) +{ + struct ureg_program *ureg = tx->ureg; + const unsigned s = tx->insn.src[0].idx; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + + if (ureg_src_is_undef(tx->regs.vT[s])) + tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + ureg_MOV(ureg, dst, tx->regs.vT[s]); /* XXX is this sufficient ? */ + + return D3D_OK; +} + +DECL_SPECIAL(TEXKILL) +{ + struct ureg_src reg; + + if (tx->version.major > 1 || tx->version.minor > 3) { + reg = tx_dst_param_as_src(tx, &tx->insn.dst[0]); + } else { + tx_texcoord_alloc(tx, tx->insn.dst[0].idx); + reg = tx->regs.vT[tx->insn.dst[0].idx]; + } + if (tx->version.major < 2) + reg = ureg_swizzle(reg, NINE_SWIZZLE4(X,Y,Z,Z)); + ureg_KILL_IF(tx->ureg, reg); + + return D3D_OK; +} + +DECL_SPECIAL(TEXBEM) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXBEML) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXREG2AR) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXREG2GB) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x2PAD) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x2TEX) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x3PAD) +{ + return D3D_OK; /* this is just padding */ +} + +DECL_SPECIAL(TEXM3x3SPEC) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x3VSPEC) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXREG2RGB) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXDP3TEX) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x2DEPTH) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXDP3) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXM3x3) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[4]; + int s; + const int m = tx->insn.dst[0].idx - 2; + const int n = tx->insn.src[0].idx; + assert(m >= 0 && m > n); + + for (s = m; s <= (m + 2); ++s) { + if (ureg_src_is_undef(tx->regs.vT[s])) + tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + src[s] = tx->regs.vT[s]; + } + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), src[0], ureg_src(tx->regs.tS[n])); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), src[1], ureg_src(tx->regs.tS[n])); + ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), src[2], ureg_src(tx->regs.tS[n])); + + switch (tx->insn.opcode) { + case D3DSIO_TEXM3x3: + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + break; + case D3DSIO_TEXM3x3TEX: + src[3] = ureg_DECL_sampler(ureg, m + 2); + tx->info->sampler_mask |= 1 << (m + 2); + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(dst), src[3]); + break; + default: + return D3DERR_INVALIDCALL; + } + return D3D_OK; +} + +DECL_SPECIAL(TEXDEPTH) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(BEM) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(TEXLD) +{ + struct ureg_program *ureg = tx->ureg; + unsigned target; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[2] = { + tx_src_param(tx, &tx->insn.src[0]), + tx_src_param(tx, &tx->insn.src[1]) + }; + assert(tx->insn.src[1].idx >= 0 && + tx->insn.src[1].idx < Elements(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + switch (tx->insn.flags) { + case 0: + ureg_TEX(ureg, dst, target, src[0], src[1]); + break; + case NINED3DSI_TEXLD_PROJECT: + ureg_TXP(ureg, dst, target, src[0], src[1]); + break; + case NINED3DSI_TEXLD_BIAS: + ureg_TXB(ureg, dst, target, src[0], src[1]); + break; + default: + assert(0); + return D3DERR_INVALIDCALL; + } + return D3D_OK; +} + +DECL_SPECIAL(TEXLD_14) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]); + const unsigned s = tx->insn.dst[0].idx; + const unsigned t = ps1x_sampler_type(tx->info, s); + + tx->info->sampler_mask |= 1 << s; + ureg_TEX(ureg, dst, t, src, ureg_DECL_sampler(ureg, s)); + + return D3D_OK; +} + +DECL_SPECIAL(TEX) +{ + struct ureg_program *ureg = tx->ureg; + const unsigned s = tx->insn.dst[0].idx; + const unsigned t = ps1x_sampler_type(tx->info, s); + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[2]; + + if (ureg_src_is_undef(tx->regs.vT[s])) + tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE); + + src[0] = tx->regs.vT[s]; + src[1] = ureg_DECL_sampler(ureg, s); + tx->info->sampler_mask |= 1 << s; + + ureg_TEX(ureg, dst, t, src[0], src[1]); + + return D3D_OK; +} + +DECL_SPECIAL(TEXLDD) +{ + unsigned target; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[4] = { + tx_src_param(tx, &tx->insn.src[0]), + tx_src_param(tx, &tx->insn.src[1]), + tx_src_param(tx, &tx->insn.src[2]), + tx_src_param(tx, &tx->insn.src[3]) + }; + assert(tx->insn.src[3].idx >= 0 && + tx->insn.src[3].idx < Elements(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + ureg_TXD(tx->ureg, dst, target, src[0], src[2], src[3], src[1]); + return D3D_OK; +} + +DECL_SPECIAL(TEXLDL) +{ + unsigned target; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src[2] = { + tx_src_param(tx, &tx->insn.src[0]), + tx_src_param(tx, &tx->insn.src[1]) + }; + assert(tx->insn.src[3].idx >= 0 && + tx->insn.src[3].idx < Elements(tx->sampler_targets)); + target = tx->sampler_targets[tx->insn.src[1].idx]; + + ureg_TXL(tx->ureg, dst, target, src[0], src[1]); + return D3D_OK; +} + +DECL_SPECIAL(SETP) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(BREAKP) +{ + STUB(D3DERR_INVALIDCALL); +} + +DECL_SPECIAL(PHASE) +{ + return D3D_OK; /* we don't care about phase */ +} + +DECL_SPECIAL(COMMENT) +{ + return D3D_OK; /* nothing to do */ +} + + +#define _OPI(o,t,vv1,vv2,pv1,pv2,d,s,h) \ + { D3DSIO_##o, TGSI_OPCODE_##t, { vv1, vv2 }, { pv1, pv2, }, d, s, h } + +struct sm1_op_info inst_table[] = +{ + _OPI(NOP, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, NULL), /* 0 */ + _OPI(MOV, MOV, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, SPECIAL(MOV_vs1x)), + _OPI(MOV, MOV, V(2,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), + _OPI(ADD, ADD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 2 */ + _OPI(SUB, SUB, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 3 */ + _OPI(MAD, MAD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 4 */ + _OPI(MUL, MUL, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 5 */ + _OPI(RCP, RCP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 6 */ + _OPI(RSQ, RSQ, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 7 */ + _OPI(DP3, DP3, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 8 */ + _OPI(DP4, DP4, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 9 */ + _OPI(MIN, MIN, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 10 */ + _OPI(MAX, MAX, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 11 */ + _OPI(SLT, SLT, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 12 */ + _OPI(SGE, SGE, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 13 */ + _OPI(EXP, EX2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 14 */ + _OPI(LOG, LG2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 15 */ + _OPI(LIT, LIT, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), /* 16 */ + _OPI(DST, DST, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 17 */ + _OPI(LRP, LRP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 18 */ + _OPI(FRC, FRC, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 19 */ + + _OPI(M4x4, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M4x4)), + _OPI(M4x3, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M4x3)), + _OPI(M3x4, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x4)), + _OPI(M3x3, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x3)), + _OPI(M3x2, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x2)), + + _OPI(CALL, CAL, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALL)), + _OPI(CALLNZ, CAL, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALLNZ)), + _OPI(LOOP, BGNLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 2, SPECIAL(LOOP)), + _OPI(RET, RET, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(RET)), + _OPI(ENDLOOP, ENDLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 0, SPECIAL(ENDLOOP)), + _OPI(LABEL, NOP, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(LABEL)), + + _OPI(DCL, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(DCL)), + + _OPI(POW, POW, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), + _OPI(CRS, XPD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* XXX: .w */ + _OPI(SGN, SSG, V(2,0), V(3,0), V(0,0), V(0,0), 1, 3, SPECIAL(SGN)), /* ignore src1,2 */ + _OPI(ABS, ABS, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), + _OPI(NRM, NRM, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(NRM)), /* NRM doesn't fit */ + + _OPI(SINCOS, SCS, V(2,0), V(2,1), V(2,0), V(2,1), 1, 3, SPECIAL(SINCOS)), + _OPI(SINCOS, SCS, V(3,0), V(3,0), V(3,0), V(3,0), 1, 1, SPECIAL(SINCOS)), + + /* More flow control */ + _OPI(REP, NOP, V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(REP)), + _OPI(ENDREP, NOP, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ENDREP)), + _OPI(IF, IF, V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(IF)), + _OPI(IFC, IF, V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(IFC)), + _OPI(ELSE, ELSE, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ELSE)), + _OPI(ENDIF, ENDIF, V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ENDIF)), + _OPI(BREAK, BRK, V(2,1), V(3,0), V(2,1), V(3,0), 0, 0, NULL), + _OPI(BREAKC, BREAKC, V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(BREAKC)), + + _OPI(MOVA, ARR, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), + + _OPI(DEFB, NOP, V(0,0), V(3,0) , V(0,0), V(3,0) , 1, 0, SPECIAL(DEFB)), + _OPI(DEFI, NOP, V(0,0), V(3,0) , V(0,0), V(3,0) , 1, 0, SPECIAL(DEFI)), + + _OPI(TEXCOORD, NOP, V(0,0), V(0,0), V(0,0), V(1,3), 1, 0, SPECIAL(TEXCOORD)), + _OPI(TEXCOORD, MOV, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXCOORD_ps14)), + _OPI(TEXKILL, KILL_IF, V(0,0), V(0,0), V(0,0), V(3,0), 1, 0, SPECIAL(TEXKILL)), + _OPI(TEX, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 0, SPECIAL(TEX)), + _OPI(TEX, TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXLD_14)), + _OPI(TEX, TEX, V(0,0), V(0,0), V(2,0), V(3,0), 1, 2, SPECIAL(TEXLD)), + _OPI(TEXBEM, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXBEM)), + _OPI(TEXBEML, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXBEML)), + _OPI(TEXREG2AR, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2AR)), + _OPI(TEXREG2GB, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2GB)), + _OPI(TEXM3x2PAD, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2PAD)), + _OPI(TEXM3x2TEX, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2TEX)), + _OPI(TEXM3x3PAD, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3PAD)), + _OPI(TEXM3x3TEX, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3)), + _OPI(TEXM3x3SPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3SPEC)), + _OPI(TEXM3x3VSPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3VSPEC)), + + _OPI(EXPP, EXP, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, NULL), + _OPI(EXPP, EX2, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), + _OPI(LOGP, LG2, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), + _OPI(CND, CND, V(0,0), V(0,0), V(0,0), V(1,4), 1, 3, SPECIAL(CND)), + + _OPI(DEF, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 0, SPECIAL(DEF)), + + /* More tex stuff */ + _OPI(TEXREG2RGB, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXREG2RGB)), + _OPI(TEXDP3TEX, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3TEX)), + _OPI(TEXM3x2DEPTH, TEX, V(0,0), V(0,0), V(1,3), V(1,3), 0, 0, SPECIAL(TEXM3x2DEPTH)), + _OPI(TEXDP3, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3)), + _OPI(TEXM3x3, TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXM3x3)), + _OPI(TEXDEPTH, TEX, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(TEXDEPTH)), + + /* Misc */ + _OPI(CMP, CMP, V(0,0), V(0,0), V(1,2), V(3,0), 1, 3, SPECIAL(CMP)), /* reversed */ + _OPI(BEM, NOP, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(BEM)), + _OPI(DP2ADD, DP2A, V(0,0), V(0,0), V(2,0), V(3,0), 1, 3, SPECIAL(DP2ADD)), /* for radeons */ + _OPI(DSX, DDX, V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL), + _OPI(DSY, DDY, V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL), + _OPI(TEXLDD, TXD, V(0,0), V(0,0), V(2,1), V(3,0), 1, 4, SPECIAL(TEXLDD)), + _OPI(SETP, NOP, V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(SETP)), + _OPI(TEXLDL, TXL, V(3,0), V(3,0), V(3,0), V(3,0), 1, 2, SPECIAL(TEXLDL)), + _OPI(BREAKP, BRK, V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(BREAKP)) +}; + +struct sm1_op_info inst_phase = + _OPI(PHASE, NOP, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(PHASE)); + +struct sm1_op_info inst_comment = + _OPI(COMMENT, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(COMMENT)); + +static void +create_op_info_map(struct shader_translator *tx) +{ + const unsigned version = (tx->version.major << 8) | tx->version.minor; + unsigned i; + + for (i = 0; i < Elements(tx->op_info_map); ++i) + tx->op_info_map[i] = -1; + + if (tx->processor == TGSI_PROCESSOR_VERTEX) { + for (i = 0; i < Elements(inst_table); ++i) { + assert(inst_table[i].sio < Elements(tx->op_info_map)); + if (inst_table[i].vert_version.min <= version && + inst_table[i].vert_version.max >= version) + tx->op_info_map[inst_table[i].sio] = i; + } + } else { + for (i = 0; i < Elements(inst_table); ++i) { + assert(inst_table[i].sio < Elements(tx->op_info_map)); + if (inst_table[i].frag_version.min <= version && + inst_table[i].frag_version.max >= version) + tx->op_info_map[inst_table[i].sio] = i; + } + } +} + +static INLINE HRESULT +NineTranslateInstruction_Generic(struct shader_translator *tx) +{ + struct ureg_dst dst[1]; + struct ureg_src src[4]; + unsigned i; + + for (i = 0; i < tx->insn.ndst && i < Elements(dst); ++i) + dst[i] = tx_dst_param(tx, &tx->insn.dst[i]); + for (i = 0; i < tx->insn.nsrc && i < Elements(src); ++i) + src[i] = tx_src_param(tx, &tx->insn.src[i]); + + ureg_insn(tx->ureg, tx->insn.info->opcode, + dst, tx->insn.ndst, + src, tx->insn.nsrc); + return D3D_OK; +} + +static INLINE DWORD +TOKEN_PEEK(struct shader_translator *tx) +{ + return *(tx->parse); +} + +static INLINE DWORD +TOKEN_NEXT(struct shader_translator *tx) +{ + return *(tx->parse)++; +} + +static INLINE void +TOKEN_JUMP(struct shader_translator *tx) +{ + if (tx->parse_next && tx->parse != tx->parse_next) { + WARN("parse(%p) != parse_next(%p) !\n", tx->parse, tx->parse_next); + tx->parse = tx->parse_next; + } +} + +static INLINE boolean +sm1_parse_eof(struct shader_translator *tx) +{ + return TOKEN_PEEK(tx) == NINED3DSP_END; +} + +static void +sm1_read_version(struct shader_translator *tx) +{ + const DWORD tok = TOKEN_NEXT(tx); + + tx->version.major = D3DSHADER_VERSION_MAJOR(tok); + tx->version.minor = D3DSHADER_VERSION_MINOR(tok); + + switch (tok >> 16) { + case NINED3D_SM1_VS: tx->processor = TGSI_PROCESSOR_VERTEX; break; + case NINED3D_SM1_PS: tx->processor = TGSI_PROCESSOR_FRAGMENT; break; + default: + DBG("Invalid shader type: %x\n", tok); + tx->processor = ~0; + break; + } +} + +/* This is just to check if we parsed the instruction properly. */ +static void +sm1_parse_get_skip(struct shader_translator *tx) +{ + const DWORD tok = TOKEN_PEEK(tx); + + if (tx->version.major >= 2) { + tx->parse_next = tx->parse + 1 /* this */ + + ((tok & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT); + } else { + tx->parse_next = NULL; /* TODO: determine from param count */ + } +} + +static void +sm1_print_comment(const char *comment, UINT size) +{ + if (!size) + return; + /* TODO */ +} + +static void +sm1_parse_comments(struct shader_translator *tx, BOOL print) +{ + DWORD tok = TOKEN_PEEK(tx); + + while ((tok & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT) + { + const char *comment = ""; + UINT size = (tok & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT; + tx->parse += size + 1; + + if (print) + sm1_print_comment(comment, size); + + tok = TOKEN_PEEK(tx); + } +} + +static void +sm1_parse_get_param(struct shader_translator *tx, DWORD *reg, DWORD *rel) +{ + *reg = TOKEN_NEXT(tx); + + if (*reg & D3DSHADER_ADDRMODE_RELATIVE) + { + if (tx->version.major < 2) + *rel = (1 << 31) | + ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) | + ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) | + (D3DSP_NOSWIZZLE << D3DSP_SWIZZLE_SHIFT); + else + *rel = TOKEN_NEXT(tx); + } +} + +static void +sm1_parse_dst_param(struct sm1_dst_param *dst, DWORD tok) +{ + dst->file = + (tok & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT | + (tok & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2; + dst->type = TGSI_RETURN_TYPE_FLOAT; + dst->idx = tok & D3DSP_REGNUM_MASK; + dst->rel = NULL; + dst->mask = (tok & NINED3DSP_WRITEMASK_MASK) >> NINED3DSP_WRITEMASK_SHIFT; + dst->mod = (tok & D3DSP_DSTMOD_MASK) >> D3DSP_DSTMOD_SHIFT; + dst->shift = (tok & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT; +} + +static void +sm1_parse_src_param(struct sm1_src_param *src, DWORD tok) +{ + src->file = + ((tok & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) | + ((tok & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2); + src->type = TGSI_RETURN_TYPE_FLOAT; + src->idx = tok & D3DSP_REGNUM_MASK; + src->rel = NULL; + src->swizzle = (tok & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT; + src->mod = (tok & D3DSP_SRCMOD_MASK) >> D3DSP_SRCMOD_SHIFT; + + switch (src->file) { + case D3DSPR_CONST2: src->file = D3DSPR_CONST; src->idx += 2048; break; + case D3DSPR_CONST3: src->file = D3DSPR_CONST; src->idx += 4096; break; + case D3DSPR_CONST4: src->file = D3DSPR_CONST; src->idx += 6144; break; + default: + break; + } +} + +static void +sm1_parse_immediate(struct shader_translator *tx, + struct sm1_src_param *imm) +{ + imm->file = NINED3DSPR_IMMEDIATE; + imm->idx = INT_MIN; + imm->rel = NULL; + imm->swizzle = NINED3DSP_NOSWIZZLE; + imm->mod = 0; + switch (tx->insn.opcode) { + case D3DSIO_DEF: + imm->type = NINED3DSPTYPE_FLOAT4; + memcpy(&imm->imm.d[0], tx->parse, 4 * sizeof(DWORD)); + tx->parse += 4; + break; + case D3DSIO_DEFI: + imm->type = NINED3DSPTYPE_INT4; + memcpy(&imm->imm.d[0], tx->parse, 4 * sizeof(DWORD)); + tx->parse += 4; + break; + case D3DSIO_DEFB: + imm->type = NINED3DSPTYPE_BOOL; + memcpy(&imm->imm.d[0], tx->parse, 1 * sizeof(DWORD)); + tx->parse += 1; + break; + default: + assert(0); + break; + } +} + +static void +sm1_read_dst_param(struct shader_translator *tx, + struct sm1_dst_param *dst, + struct sm1_src_param *rel) +{ + DWORD tok_dst, tok_rel = 0; + + sm1_parse_get_param(tx, &tok_dst, &tok_rel); + sm1_parse_dst_param(dst, tok_dst); + if (tok_dst & D3DSHADER_ADDRMODE_RELATIVE) { + sm1_parse_src_param(rel, tok_rel); + dst->rel = rel; + } +} + +static void +sm1_read_src_param(struct shader_translator *tx, + struct sm1_src_param *src, + struct sm1_src_param *rel) +{ + DWORD tok_src, tok_rel = 0; + + sm1_parse_get_param(tx, &tok_src, &tok_rel); + sm1_parse_src_param(src, tok_src); + if (tok_src & D3DSHADER_ADDRMODE_RELATIVE) { + assert(rel); + sm1_parse_src_param(rel, tok_rel); + src->rel = rel; + } +} + +static void +sm1_read_semantic(struct shader_translator *tx, + struct sm1_semantic *sem) +{ + const DWORD tok_usg = TOKEN_NEXT(tx); + const DWORD tok_dst = TOKEN_NEXT(tx); + + sem->sampler_type = (tok_usg & D3DSP_TEXTURETYPE_MASK) >> D3DSP_TEXTURETYPE_SHIFT; + sem->usage = (tok_usg & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT; + sem->usage_idx = (tok_usg & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT; + + sm1_parse_dst_param(&sem->reg, tok_dst); +} + +static void +sm1_parse_instruction(struct shader_translator *tx) +{ + struct sm1_instruction *insn = &tx->insn; + DWORD tok; + struct sm1_op_info *info = NULL; + unsigned i; + + sm1_parse_comments(tx, TRUE); + sm1_parse_get_skip(tx); + + tok = TOKEN_NEXT(tx); + + insn->opcode = tok & D3DSI_OPCODE_MASK; + insn->flags = (tok & NINED3DSIO_OPCODE_FLAGS_MASK) >> NINED3DSIO_OPCODE_FLAGS_SHIFT; + insn->coissue = !!(tok & D3DSI_COISSUE); + insn->predicated = !!(tok & NINED3DSHADER_INST_PREDICATED); + + if (insn->opcode < Elements(tx->op_info_map)) { + int k = tx->op_info_map[insn->opcode]; + if (k >= 0) { + assert(k < Elements(inst_table)); + info = &inst_table[k]; + } + } else { + if (insn->opcode == D3DSIO_PHASE) info = &inst_phase; + if (insn->opcode == D3DSIO_COMMENT) info = &inst_comment; + } + if (!info) { + DBG("illegal or unhandled opcode: %08x\n", insn->opcode); + TOKEN_JUMP(tx); + return; + } + insn->info = info; + insn->ndst = info->ndst; + insn->nsrc = info->nsrc; + + assert(!insn->predicated && "TODO: predicated instructions"); + + /* check version */ + { + unsigned min = IS_VS ? info->vert_version.min : info->frag_version.min; + unsigned max = IS_VS ? info->vert_version.max : info->frag_version.max; + unsigned ver = (tx->version.major << 8) | tx->version.minor; + if (ver < min || ver > max) { + DBG("opcode not supported in this shader version: %x <= %x <= %x\n", + min, ver, max); + return; + } + } + + for (i = 0; i < insn->ndst; ++i) + sm1_read_dst_param(tx, &insn->dst[i], &insn->dst_rel[i]); + if (insn->predicated) + sm1_read_src_param(tx, &insn->pred, NULL); + for (i = 0; i < insn->nsrc; ++i) + sm1_read_src_param(tx, &insn->src[i], &insn->src_rel[i]); + + /* parse here so we can dump them before processing */ + if (insn->opcode == D3DSIO_DEF || + insn->opcode == D3DSIO_DEFI || + insn->opcode == D3DSIO_DEFB) + sm1_parse_immediate(tx, &tx->insn.src[0]); + + sm1_dump_instruction(insn, tx->cond_depth + tx->loop_depth); + sm1_instruction_check(insn); + + if (info->handler) + info->handler(tx); + else + NineTranslateInstruction_Generic(tx); + tx_apply_dst0_modifiers(tx); + + tx->num_scratch = 0; /* reset */ + + TOKEN_JUMP(tx); +} + +static void +tx_ctor(struct shader_translator *tx, struct nine_shader_info *info) +{ + unsigned i; + + tx->info = info; + + tx->byte_code = info->byte_code; + tx->parse = info->byte_code; + + for (i = 0; i < Elements(info->input_map); ++i) + info->input_map[i] = NINE_DECLUSAGE_NONE; + info->num_inputs = 0; + + info->position_t = FALSE; + info->point_size = FALSE; + + tx->info->const_used_size = 0; + + info->sampler_mask = 0x0; + info->rt_mask = 0x0; + + info->lconstf.data = NULL; + info->lconstf.ranges = NULL; + + for (i = 0; i < Elements(tx->regs.aL); ++i) { + tx->regs.aL[i] = ureg_dst_undef(); + tx->regs.rL[i] = ureg_dst_undef(); + } + tx->regs.a = ureg_dst_undef(); + tx->regs.p = ureg_dst_undef(); + tx->regs.oDepth = ureg_dst_undef(); + tx->regs.vPos = ureg_src_undef(); + tx->regs.vFace = ureg_src_undef(); + for (i = 0; i < Elements(tx->regs.o); ++i) + tx->regs.o[i] = ureg_dst_undef(); + for (i = 0; i < Elements(tx->regs.oCol); ++i) + tx->regs.oCol[i] = ureg_dst_undef(); + for (i = 0; i < Elements(tx->regs.vC); ++i) + tx->regs.vC[i] = ureg_src_undef(); + for (i = 0; i < Elements(tx->regs.vT); ++i) + tx->regs.vT[i] = ureg_src_undef(); + + for (i = 0; i < Elements(tx->lconsti); ++i) + tx->lconsti[i].idx = -1; + for (i = 0; i < Elements(tx->lconstb); ++i) + tx->lconstb[i].idx = -1; + + sm1_read_version(tx); + + info->version = (tx->version.major << 4) | tx->version.minor; + + create_op_info_map(tx); +} + +static void +tx_dtor(struct shader_translator *tx) +{ + if (tx->num_inst_labels) + FREE(tx->inst_labels); + if (tx->lconstf) + FREE(tx->lconstf); + if (tx->regs.r) + FREE(tx->regs.r); + FREE(tx); +} + +static INLINE unsigned +tgsi_processor_from_type(unsigned shader_type) +{ + switch (shader_type) { + case PIPE_SHADER_VERTEX: return TGSI_PROCESSOR_VERTEX; + case PIPE_SHADER_FRAGMENT: return TGSI_PROCESSOR_FRAGMENT; + default: + return ~0; + } +} + +#define GET_CAP(n) device->screen->get_param( \ + device->screen, PIPE_CAP_##n) +#define GET_SHADER_CAP(n) device->screen->get_shader_param( \ + device->screen, info->type, PIPE_SHADER_CAP_##n) + +HRESULT +nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info) +{ + struct shader_translator *tx; + HRESULT hr = D3D_OK; + const unsigned processor = tgsi_processor_from_type(info->type); + + user_assert(processor != ~0, D3DERR_INVALIDCALL); + + tx = CALLOC_STRUCT(shader_translator); + if (!tx) + return E_OUTOFMEMORY; + tx_ctor(tx, info); + + if (((tx->version.major << 16) | tx->version.minor) > 0x00030000) { + hr = D3DERR_INVALIDCALL; + DBG("Unsupported shader version: %u.%u !\n", + tx->version.major, tx->version.minor); + goto out; + } + if (tx->processor != processor) { + hr = D3DERR_INVALIDCALL; + DBG("Shader type mismatch: %u / %u !\n", tx->processor, processor); + goto out; + } + DUMP("%s%u.%u\n", processor == TGSI_PROCESSOR_VERTEX ? "VS" : "PS", + tx->version.major, tx->version.minor); + + tx->ureg = ureg_create(processor); + if (!tx->ureg) { + hr = E_OUTOFMEMORY; + goto out; + } + tx_decl_constants(tx); + + tx->native_integers = GET_SHADER_CAP(INTEGERS); + tx->inline_subroutines = !GET_SHADER_CAP(SUBROUTINES); + tx->lower_preds = !GET_SHADER_CAP(MAX_PREDS); + tx->want_texcoord = GET_CAP(TGSI_TEXCOORD); + tx->shift_wpos = !GET_CAP(TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + tx->texcoord_sn = tx->want_texcoord ? + TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; + + /* VS must always write position. Declare it here to make it the 1st output. + * (Some drivers like nv50 are buggy and rely on that.) + */ + if (IS_VS) { + tx->regs.oPos = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_POSITION, 0); + } else { + ureg_property_fs_coord_origin(tx->ureg, TGSI_FS_COORD_ORIGIN_UPPER_LEFT); + if (!tx->shift_wpos) + ureg_property_fs_coord_pixel_center(tx->ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + } + + if (!ureg_dst_is_undef(tx->regs.oPts)) + info->point_size = TRUE; + + while (!sm1_parse_eof(tx)) + sm1_parse_instruction(tx); + tx->parse++; /* for byte_size */ + + if (IS_PS && (tx->version.major < 2) && tx->num_temp) { + ureg_MOV(tx->ureg, ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 0), + ureg_src(tx->regs.r[0])); + info->rt_mask |= 0x1; + } + + if (info->position_t) + ureg_property_vs_window_space_position(tx->ureg, TRUE); + + ureg_END(tx->ureg); + + if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) { + unsigned count; + const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, &count); + tgsi_dump(toks, 0); + ureg_free_tokens(toks); + } + + /* record local constants */ + if (tx->num_lconstf && tx->indirect_const_access) { + struct nine_range *ranges; + float *data; + int *indices; + unsigned i, k, n; + + hr = E_OUTOFMEMORY; + + data = MALLOC(tx->num_lconstf * 4 * sizeof(float)); + if (!data) + goto out; + info->lconstf.data = data; + + indices = MALLOC(tx->num_lconstf * sizeof(indices[0])); + if (!indices) + goto out; + + /* lazy sort, num_lconstf should be small */ + for (n = 0; n < tx->num_lconstf; ++n) { + for (k = 0, i = 0; i < tx->num_lconstf; ++i) { + if (tx->lconstf[i].idx < tx->lconstf[k].idx) + k = i; + } + indices[n] = tx->lconstf[k].idx; + memcpy(&data[n * 4], &tx->lconstf[k].imm.f[0], 4 * sizeof(float)); + tx->lconstf[k].idx = INT_MAX; + } + + /* count ranges */ + for (n = 1, i = 1; i < tx->num_lconstf; ++i) + if (indices[i] != indices[i - 1] + 1) + ++n; + ranges = MALLOC(n * sizeof(ranges[0])); + if (!ranges) { + FREE(indices); + goto out; + } + info->lconstf.ranges = ranges; + + k = 0; + ranges[k].bgn = indices[0]; + for (i = 1; i < tx->num_lconstf; ++i) { + if (indices[i] != indices[i - 1] + 1) { + ranges[k].next = &ranges[k + 1]; + ranges[k].end = indices[i - 1] + 1; + ++k; + ranges[k].bgn = indices[i]; + } + } + ranges[k].end = indices[i - 1] + 1; + ranges[k].next = NULL; + assert(n == (k + 1)); + + FREE(indices); + hr = D3D_OK; + } + + if (tx->indirect_const_access) + info->const_used_size = ~0; + + info->cso = ureg_create_shader_and_destroy(tx->ureg, device->pipe); + if (!info->cso) { + hr = D3DERR_DRIVERINTERNALERROR; + FREE(info->lconstf.data); + FREE(info->lconstf.ranges); + goto out; + } + + info->byte_size = (tx->parse - tx->byte_code) * sizeof(DWORD); +out: + tx_dtor(tx); + return hr; +} diff --git a/src/gallium/state_trackers/nine/nine_shader.h b/src/gallium/state_trackers/nine/nine_shader.h new file mode 100644 index 00000000000..21824086490 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_shader.h @@ -0,0 +1,142 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_SHADER_H_ +#define _NINE_SHADER_H_ + +#include "d3d9types.h" +#include "d3d9caps.h" +#include "nine_defines.h" +#include "pipe/p_state.h" /* PIPE_MAX_ATTRIBS */ +#include "util/u_memory.h" + +struct NineDevice9; + +struct nine_lconstf /* NOTE: both pointers should be FREE'd by the user */ +{ + struct nine_range *ranges; /* single MALLOC, but next-pointers valid */ + float *data; +}; + +struct nine_shader_info +{ + unsigned type; /* in, PIPE_SHADER_x */ + + uint8_t version; /* (major << 4) | minor */ + + const DWORD *byte_code; /* in, pointer to shader tokens */ + DWORD byte_size; /* out, size of data at byte_code */ + + void *cso; /* out, pipe cso for bind_vs,fs_state */ + + uint8_t input_map[PIPE_MAX_ATTRIBS]; /* VS input -> NINE_DECLUSAGE_x */ + uint8_t num_inputs; /* there may be unused inputs (NINE_DECLUSAGE_NONE) */ + + boolean position_t; /* out, true if VP writes pre-transformed position */ + boolean point_size; /* out, true if VP writes point size */ + + uint32_t sampler_ps1xtypes; /* 2 bits per sampler */ + uint16_t sampler_mask; /* out, which samplers are being used */ + uint16_t sampler_mask_shadow; /* in, which samplers use depth compare */ + uint8_t rt_mask; /* out, which render targets are being written */ + + unsigned const_i_base; /* in vec4 (16 byte) units */ + unsigned const_b_base; /* in vec4 (16 byte) units */ + unsigned const_used_size; + + struct nine_lconstf lconstf; /* out, NOTE: members to be free'd by user */ +}; + +static INLINE void +nine_info_mark_const_f_used(struct nine_shader_info *info, int idx) +{ + unsigned size = (idx + 1) * 16; + + if (info->const_used_size < size) + info->const_used_size = size; +} +static INLINE void +nine_info_mark_const_i_used(struct nine_shader_info *info, int idx) +{ + unsigned size = (info->const_i_base + (idx + 1)) * 16; + + if (info->const_used_size < size) + info->const_used_size = size; +} +static INLINE void +nine_info_mark_const_b_used(struct nine_shader_info *info, int idx) +{ + unsigned size = (info->const_b_base + ((idx + 4) / 4)) * 16; + + if (info->const_used_size < size) + info->const_used_size = size; +} + +HRESULT +nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *); + + +struct nine_shader_variant +{ + struct nine_shader_variant *next; + void *cso; + uint32_t key; +}; + +static INLINE void * +nine_shader_variant_get(struct nine_shader_variant *list, uint32_t key) +{ + while (list->key != key && list->next) + list = list->next; + if (list->key == key) + return list->cso; + return NULL; +} + +static INLINE boolean +nine_shader_variant_add(struct nine_shader_variant *list, + uint32_t key, void *cso) +{ + while (list->next) { + assert(list->key != key); + list = list->next; + } + list->next = MALLOC_STRUCT(nine_shader_variant); + if (!list->next) + return FALSE; + list->next->next = NULL; + list->next->key = key; + list->next->cso = cso; + return TRUE; +} + +static INLINE void +nine_shader_variants_free(struct nine_shader_variant *list) +{ + while (list->next) { + struct nine_shader_variant *ptr = list->next; + list->next = ptr->next; + FREE(ptr); + } +} + +#endif /* _NINE_SHADER_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c new file mode 100644 index 00000000000..0215d080808 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_state.c @@ -0,0 +1,1489 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * Copyright 2013 Christoph Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "basetexture9.h" +#include "indexbuffer9.h" +#include "surface9.h" +#include "vertexdeclaration9.h" +#include "vertexshader9.h" +#include "pixelshader9.h" +#include "nine_pipe.h" +#include "nine_ff.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "cso_cache/cso_context.h" +#include "util/u_math.h" + +#define DBG_CHANNEL DBG_DEVICE + +static uint32_t +update_framebuffer(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + struct pipe_framebuffer_state *fb = &device->state.fb; + unsigned i; + unsigned w = 0, h = 0; /* no surface can have width or height 0 */ + + const int sRGB = state->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0; + + DBG("\n"); + + state->rt_mask = 0x0; + fb->nr_cbufs = 0; + + for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { + if (state->rt[i] && state->rt[i]->desc.Format != D3DFMT_NULL) { + struct NineSurface9 *rt = state->rt[i]; + fb->cbufs[i] = NineSurface9_GetSurface(rt, sRGB); + state->rt_mask |= 1 << i; + fb->nr_cbufs = i + 1; + if (w) { + w = MIN2(w, rt->desc.Width); + h = MIN2(h, rt->desc.Height); + } else { + w = rt->desc.Width; + h = rt->desc.Height; + } + if (unlikely(rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)) { + assert(rt->texture == D3DRTYPE_TEXTURE || + rt->texture == D3DRTYPE_CUBETEXTURE); + NineBaseTexture9(rt->base.base.container)->dirty_mip = TRUE; + } + } else { + /* Color outputs must match RT slot, + * drivers will have to handle NULL entries for GL, too. + */ + fb->cbufs[i] = NULL; + } + } + + if (state->ds) { + fb->zsbuf = NineSurface9_GetSurface(state->ds, 0); + if (w) { + w = MIN2(w, state->ds->desc.Width); + h = MIN2(h, state->ds->desc.Height); + } else { + w = state->ds->desc.Width; + h = state->ds->desc.Height; + } + } else { + fb->zsbuf = NULL; + } + + fb->width = w; + fb->height = h; + + pipe->set_framebuffer_state(pipe, fb); /* XXX: cso ? */ + + if (fb->zsbuf) { + DWORD scale; + switch (fb->zsbuf->format) { + case PIPE_FORMAT_Z32_FLOAT: + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: + scale = fui(1.0f); + break; + case PIPE_FORMAT_Z16_UNORM: + scale = fui((float)(1 << 16)); + break; + default: + scale = fui((float)(1 << 24)); + break; + } + if (state->rs[NINED3DRS_ZBIASSCALE] != scale) { + state->rs[NINED3DRS_ZBIASSCALE] = scale; + state->changed.group |= NINE_STATE_RASTERIZER; + } + } + +#ifdef DEBUG + if (state->rt_mask & (state->ps ? ~state->ps->rt_mask : 0)) + WARN_ONCE("FIXME: writing undefined values to cbufs 0x%x\n", + state->rt_mask & ~state->ps->rt_mask); +#endif + + return state->changed.group; +} + +static void +update_viewport(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + const D3DVIEWPORT9 *vport = &device->state.viewport; + struct pipe_viewport_state pvport; + + /* XXX: + * I hope D3D clip coordinates are still + * -1 .. +1 for X,Y and + * 0 .. +1 for Z (use pipe_rasterizer_state.clip_halfz) + */ + pvport.scale[0] = (float)vport->Width * 0.5f; + pvport.scale[1] = (float)vport->Height * -0.5f; + pvport.scale[2] = vport->MaxZ - vport->MinZ; + pvport.scale[3] = 1.0f; + pvport.translate[0] = (float)vport->Width * 0.5f + (float)vport->X; + pvport.translate[1] = (float)vport->Height * 0.5f + (float)vport->Y; + pvport.translate[2] = vport->MinZ; + pvport.translate[3] = 0.0f; + + pipe->set_viewport_states(pipe, 0, 1, &pvport); +} + +static INLINE void +update_scissor(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + + pipe->set_scissor_states(pipe, 0, 1, &device->state.scissor); +} + +static INLINE void +update_blend(struct NineDevice9 *device) +{ + nine_convert_blend_state(device->cso, device->state.rs); +} + +static INLINE void +update_dsa(struct NineDevice9 *device) +{ + nine_convert_dsa_state(device->cso, device->state.rs); +} + +static INLINE void +update_rasterizer(struct NineDevice9 *device) +{ + nine_convert_rasterizer_state(device->cso, device->state.rs); +} + +/* Loop through VS inputs and pick the vertex elements with the declared + * usage from the vertex declaration, then insert the instance divisor from + * the stream source frequency setting. + */ +static void +update_vertex_elements(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + const struct NineVertexDeclaration9 *vdecl = device->state.vdecl; + const struct NineVertexShader9 *vs; + unsigned n, l, b; + struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS]; + + state->stream_usage_mask = 0; + + vs = device->state.vs ? device->state.vs : device->ff.vs; + + if (!vdecl) /* no inputs */ + return; + for (n = 0; n < vs->num_inputs; ++n) { + DBG("looking up input %u (usage %u) from vdecl(%p)\n", + n, vs->input_map[n].ndecl, vdecl); + + assert(vs->input_map[n].ndecl < Elements(vdecl->usage_map)); + l = vdecl->usage_map[vs->input_map[n].ndecl]; + + if (likely(l < vdecl->nelems)) { + ve[n] = vdecl->elems[l]; + b = ve[n].vertex_buffer_index; + state->stream_usage_mask |= 1 << b; + /* XXX wine just uses 1 here: */ + if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA) + ve[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF; + } else { + /* TODO: + * If drivers don't want to handle this, insert a dummy buffer. + * But on which stream ? + */ + /* no data, disable */ + ve[n].src_format = PIPE_FORMAT_NONE; + ve[n].src_offset = 0; + ve[n].instance_divisor = 0; + ve[n].vertex_buffer_index = 0; + } + } + cso_set_vertex_elements(device->cso, vs->num_inputs, ve); + + state->changed.stream_freq = 0; +} + +static INLINE uint32_t +update_shader_variant_keys(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + uint32_t mask = 0; + uint32_t vs_key = state->samplers_shadow; + uint32_t ps_key = state->samplers_shadow; + + vs_key = (vs_key & NINE_VS_SAMPLERS_MASK) >> NINE_SAMPLER_VS(0); + ps_key = (ps_key & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0); + + if (state->vs) vs_key &= state->vs->sampler_mask; + if (state->ps) { + if (unlikely(state->ps->byte_code.version < 0x20)) { + /* no depth textures, but variable targets */ + uint32_t m = state->ps->sampler_mask; + ps_key = 0; + while (m) { + int s = ffs(m) - 1; + m &= ~(1 << s); + ps_key |= (state->texture[s] ? state->texture[s]->pstype : 1) << (s * 2); + } + } else { + ps_key &= state->ps->sampler_mask; + } + } + + if (state->vs && state->vs_key != vs_key) { + state->vs_key = vs_key; + mask |= NINE_STATE_VS; + } + if (state->ps && state->ps_key != ps_key) { + state->ps_key = ps_key; + mask |= NINE_STATE_PS; + } + return mask; +} + +static INLINE uint32_t +update_vs(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct NineVertexShader9 *vs = state->vs; + + /* likely because we dislike FF */ + if (likely(vs)) { + state->cso.vs = NineVertexShader9_GetVariant(vs, state->vs_key); + } else { + vs = device->ff.vs; + state->cso.vs = vs->variant.cso; + } + device->pipe->bind_vs_state(device->pipe, state->cso.vs); + + if (state->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) { + state->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size; + return NINE_STATE_RASTERIZER; + } +#ifdef DEBUG + { + unsigned s, mask = vs->sampler_mask; + for (s = 0; mask; ++s, mask >>= 1) + if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_VS(s)])) + WARN_ONCE("FIXME: unbound sampler should return alpha=1\n"); + } +#endif + return 0; +} + +static INLINE uint32_t +update_ps(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct NinePixelShader9 *ps = state->ps; + + if (likely(ps)) { + state->cso.ps = NinePixelShader9_GetVariant(ps, state->ps_key); + } else { + ps = device->ff.ps; + state->cso.ps = ps->variant.cso; + } + device->pipe->bind_fs_state(device->pipe, state->cso.ps); + +#ifdef DEBUG + { + unsigned s, mask = ps->sampler_mask; + for (s = 0; mask; ++s, mask >>= 1) + if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_PS(s)])) + WARN_ONCE("FIXME: unbound sampler should return alpha=1\n"); + if (device->state.rt_mask & ~ps->rt_mask) + WARN_ONCE("FIXME: writing undefined values to cbufs 0x%x\n", + device->state.rt_mask & ~ps->rt_mask); + } +#endif + return 0; +} + +#define DO_UPLOAD_CONST_F(buf,p,c,d) \ + do { \ + DBG("upload ConstantF [%u .. %u]\n", x, (x) + (c) - 1); \ + box.x = (p) * 4 * sizeof(float); \ + box.width = (c) * 4 * sizeof(float); \ + pipe->transfer_inline_write(pipe, buf, 0, usage, &box, &((d)[p * 4]), \ + 0, 0); \ + } while(0) + +/* OK, this is a bit ugly ... */ +static void +update_constants(struct NineDevice9 *device, unsigned shader_type) +{ + struct pipe_context *pipe = device->pipe; + struct pipe_resource *buf; + struct pipe_box box; + const void *data; + const float *const_f; + const int *const_i; + const BOOL *const_b; + uint32_t data_b[NINE_MAX_CONST_B]; + uint32_t b_true; + uint16_t dirty_i; + uint16_t dirty_b; + const unsigned usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; + unsigned x = 0; /* silence warning */ + unsigned i, c, n; + const struct nine_lconstf *lconstf; + struct nine_range *r, *p; + + box.y = 0; + box.z = 0; + box.height = 1; + box.depth = 1; + + if (shader_type == PIPE_SHADER_VERTEX) { + DBG("VS\n"); + buf = device->constbuf_vs; + + const_f = device->state.vs_const_f; + for (p = r = device->state.changed.vs_const_f; r; p = r, r = r->next) + DO_UPLOAD_CONST_F(buf, r->bgn, r->end - r->bgn, const_f); + if (p) { + nine_range_pool_put_chain(&device->range_pool, + device->state.changed.vs_const_f, p); + device->state.changed.vs_const_f = NULL; + } + + dirty_i = device->state.changed.vs_const_i; + device->state.changed.vs_const_i = 0; + const_i = &device->state.vs_const_i[0][0]; + + dirty_b = device->state.changed.vs_const_b; + device->state.changed.vs_const_b = 0; + const_b = device->state.vs_const_b; + b_true = device->vs_bool_true; + + lconstf = &device->state.vs->lconstf; + device->state.ff.clobber.vs_const = TRUE; + device->state.changed.group &= ~NINE_STATE_VS_CONST; + } else { + DBG("PS\n"); + buf = device->constbuf_ps; + + const_f = device->state.ps_const_f; + for (p = r = device->state.changed.ps_const_f; r; p = r, r = r->next) + DO_UPLOAD_CONST_F(buf, r->bgn, r->end - r->bgn, const_f); + if (p) { + nine_range_pool_put_chain(&device->range_pool, + device->state.changed.ps_const_f, p); + device->state.changed.ps_const_f = NULL; + } + + dirty_i = device->state.changed.ps_const_i; + device->state.changed.ps_const_i = 0; + const_i = &device->state.ps_const_i[0][0]; + + dirty_b = device->state.changed.ps_const_b; + device->state.changed.vs_const_b = 0; + const_b = device->state.ps_const_b; + b_true = device->ps_bool_true; + + lconstf = &device->state.ps->lconstf; + device->state.ff.clobber.ps_const = TRUE; + device->state.changed.group &= ~NINE_STATE_PS_CONST; + } + + /* write range from min to max changed, it's not much data */ + /* bool1 */ + if (dirty_b) { + c = util_last_bit(dirty_b); + i = ffs(dirty_b) - 1; + x = buf->width0 - (NINE_MAX_CONST_B - i) * 4; + c -= i; + for (n = 0; n < c; ++n, ++i) + data_b[n] = const_b[i] ? b_true : 0; + box.x = x; + box.width = n * 4; + DBG("upload ConstantB [%u .. %u]\n", x, x + n - 1); + pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data_b, 0, 0); + } + + /* int4 */ + for (c = 0, i = 0; dirty_i; i++, dirty_i >>= 1) { + if (dirty_i & 1) { + if (!c) + x = i; + ++c; + } else + if (c) { + DBG("upload ConstantI [%u .. %u]\n", x, x + c - 1); + data = &const_i[x * 4]; + box.x = buf->width0 - (NINE_MAX_CONST_I * 4 + NINE_MAX_CONST_B) * 4; + box.x += x * 4 * sizeof(int); + box.width = c * 4 * sizeof(int); + c = 0; + pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0); + } + } + if (c) { + DBG("upload ConstantI [%u .. %u]\n", x, x + c - 1); + data = &const_i[x * 4]; + box.x = buf->width0 - (NINE_MAX_CONST_I * 4 + NINE_MAX_CONST_B) * 4; + box.x += x * 4 * sizeof(int); + box.width = c * 4 * sizeof(int); + pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0); + } + + /* TODO: only upload these when shader itself changes */ + if (lconstf->ranges) { + unsigned n = 0; + struct nine_range *r = lconstf->ranges; + while (r) { + box.x = r->bgn * 4 * sizeof(float); + n += r->end - r->bgn; + box.width = (r->end - r->bgn) * 4 * sizeof(float); + data = &lconstf->data[4 * n]; + pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0); + r = r->next; + } + } +} + +static void +update_vs_constants_userbuf(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct pipe_context *pipe = device->pipe; + struct pipe_constant_buffer cb; + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = device->state.vs->const_used_size; + cb.user_buffer = device->state.vs_const_f; + + if (!cb.buffer_size) + return; + + if (state->changed.vs_const_i) { + int *idst = (int *)&state->vs_const_f[4 * device->max_vs_const_f]; + memcpy(idst, state->vs_const_i, sizeof(state->vs_const_i)); + state->changed.vs_const_i = 0; + } + if (state->changed.vs_const_b) { + int *idst = (int *)&state->vs_const_f[4 * device->max_vs_const_f]; + uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I]; + int i; + for (i = 0; i < NINE_MAX_CONST_B; ++i) + bdst[i] = state->vs_const_b[i] ? device->vs_bool_true : 0; + state->changed.vs_const_b = 0; + } + +#ifdef DEBUG + if (device->state.vs->lconstf.ranges) { + /* TODO: Can we make it so that we don't have to copy everything ? */ + const struct nine_lconstf *lconstf = &device->state.vs->lconstf; + const struct nine_range *r = lconstf->ranges; + unsigned n = 0; + float *dst = (float *)MALLOC(cb.buffer_size); + float *src = (float *)cb.user_buffer; + memcpy(dst, src, cb.buffer_size); + while (r) { + unsigned p = r->bgn; + unsigned c = r->end - r->bgn; + memcpy(&dst[p * 4], &lconstf->data[n * 4], c * 4 * sizeof(float)); + n += c; + r = r->next; + } + cb.user_buffer = dst; + } +#endif + + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); + +#ifdef DEBUG + if (device->state.vs->lconstf.ranges) + FREE((void *)cb.user_buffer); +#endif + + if (device->state.changed.vs_const_f) { + struct nine_range *r = device->state.changed.vs_const_f; + struct nine_range *p = r; + while (p->next) + p = p->next; + nine_range_pool_put_chain(&device->range_pool, r, p); + device->state.changed.vs_const_f = NULL; + } + state->changed.group &= ~NINE_STATE_VS_CONST; +} + +static void +update_ps_constants_userbuf(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + struct pipe_context *pipe = device->pipe; + struct pipe_constant_buffer cb; + cb.buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = device->state.ps->const_used_size; + cb.user_buffer = device->state.ps_const_f; + + if (!cb.buffer_size) + return; + + if (state->changed.ps_const_i) { + int *idst = (int *)&state->ps_const_f[4 * device->max_ps_const_f]; + memcpy(idst, state->ps_const_i, sizeof(state->ps_const_i)); + state->changed.ps_const_i = 0; + } + if (state->changed.ps_const_b) { + int *idst = (int *)&state->ps_const_f[4 * device->max_ps_const_f]; + uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I]; + int i; + for (i = 0; i < NINE_MAX_CONST_B; ++i) + bdst[i] = state->ps_const_b[i] ? device->ps_bool_true : 0; + state->changed.ps_const_b = 0; + } + +#ifdef DEBUG + if (device->state.ps->lconstf.ranges) { + /* TODO: Can we make it so that we don't have to copy everything ? */ + const struct nine_lconstf *lconstf = &device->state.ps->lconstf; + const struct nine_range *r = lconstf->ranges; + unsigned n = 0; + float *dst = (float *)MALLOC(cb.buffer_size); + float *src = (float *)cb.user_buffer; + memcpy(dst, src, cb.buffer_size); + while (r) { + unsigned p = r->bgn; + unsigned c = r->end - r->bgn; + memcpy(&dst[p * 4], &lconstf->data[n * 4], c * 4 * sizeof(float)); + n += c; + r = r->next; + } + cb.user_buffer = dst; + } +#endif + + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); + +#ifdef DEBUG + if (device->state.ps->lconstf.ranges) + FREE((void *)cb.user_buffer); +#endif + + if (device->state.changed.ps_const_f) { + struct nine_range *r = device->state.changed.ps_const_f; + struct nine_range *p = r; + while (p->next) + p = p->next; + nine_range_pool_put_chain(&device->range_pool, r, p); + device->state.changed.ps_const_f = NULL; + } + state->changed.group &= ~NINE_STATE_PS_CONST; +} + +static void +update_vertex_buffers(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + uint32_t mask = state->changed.vtxbuf; + unsigned i; + unsigned start; + unsigned count = 0; + + DBG("mask=%x\n", mask); + + for (i = 0; mask; mask >>= 1, ++i) { + if (mask & 1) { + if (!count) + start = i; + ++count; + } else { + if (count) + pipe->set_vertex_buffers(pipe, + start, count, &state->vtxbuf[start]); + count = 0; + } + } + if (count) + pipe->set_vertex_buffers(pipe, start, count, &state->vtxbuf[start]); + + state->changed.vtxbuf = 0; +} + +static INLINE void +update_index_buffer(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + if (device->state.idxbuf) + pipe->set_index_buffer(pipe, &device->state.idxbuf->buffer); + else + pipe->set_index_buffer(pipe, NULL); +} + +/* TODO: only go through dirty textures */ +static void +validate_textures(struct NineDevice9 *device) +{ + struct NineBaseTexture9 *tex, *ptr; + LIST_FOR_EACH_ENTRY_SAFE(tex, ptr, &device->update_textures, list) { + list_delinit(&tex->list); + NineBaseTexture9_Validate(tex); + } +} + +static INLINE boolean +update_sampler_derived(struct nine_state *state, unsigned s) +{ + boolean changed = FALSE; + + if (state->samp[s][NINED3DSAMP_SHADOW] != state->texture[s]->shadow) { + changed = TRUE; + state->samp[s][NINED3DSAMP_SHADOW] = state->texture[s]->shadow; + } + + if (state->samp[s][D3DSAMP_MIPFILTER] != D3DTEXF_NONE) { + int lod = state->samp[s][D3DSAMP_MAXMIPLEVEL] - state->texture[s]->lod; + if (lod < 0) + lod = 0; + if (state->samp[s][NINED3DSAMP_MINLOD] != lod) { + changed = TRUE; + state->samp[s][NINED3DSAMP_MINLOD] = lod; + } + } else { + state->changed.sampler[s] &= ~0x300; /* lod changes irrelevant */ + } + + return changed; +} + +/* TODO: add sRGB override to pipe_sampler_state ? */ +static void +update_textures_and_samplers(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + struct pipe_sampler_view *view[NINE_MAX_SAMPLERS]; + unsigned num_textures; + unsigned i; + boolean commit_samplers; + + /* TODO: Can we reduce iterations here ? */ + + commit_samplers = FALSE; + for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_PS; ++i) { + const unsigned s = NINE_SAMPLER_PS(i); + int sRGB; + if (!state->texture[s]) { + view[i] = NULL; +#ifdef DEBUG + if (state->ps && state->ps->sampler_mask & (1 << i)) + WARN_ONCE("FIXME: unbound sampler should return alpha=1\n"); +#endif + continue; + } + sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0; + + view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB); + num_textures = i + 1; + + if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) { + state->changed.sampler[s] = 0; + commit_samplers = TRUE; + nine_convert_sampler_state(device->cso, s, state->samp[s]); + } + } + if (state->changed.texture & NINE_PS_SAMPLERS_MASK) + pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, + num_textures, view); + + if (commit_samplers) + cso_single_sampler_done(device->cso, PIPE_SHADER_FRAGMENT); + + commit_samplers = FALSE; + for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_VS; ++i) { + const unsigned s = NINE_SAMPLER_VS(i); + int sRGB; + if (!state->texture[s]) { + view[i] = NULL; +#ifdef DEBUG + if (state->vs && state->vs->sampler_mask & (1 << i)) + WARN_ONCE("FIXME: unbound sampler should return alpha=1\n"); +#endif + continue; + } + sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0; + + view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB); + num_textures = i + 1; + + if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) { + state->changed.sampler[s] = 0; + commit_samplers = TRUE; + nine_convert_sampler_state(device->cso, s, state->samp[s]); + } + } + if (state->changed.texture & NINE_VS_SAMPLERS_MASK) + pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, + num_textures, view); + + if (commit_samplers) + cso_single_sampler_done(device->cso, PIPE_SHADER_VERTEX); + + state->changed.texture = 0; +} + + +#define NINE_STATE_FREQ_GROUP_0 \ + (NINE_STATE_FB | \ + NINE_STATE_VIEWPORT | \ + NINE_STATE_SCISSOR | \ + NINE_STATE_BLEND | \ + NINE_STATE_DSA | \ + NINE_STATE_RASTERIZER | \ + NINE_STATE_VS | \ + NINE_STATE_PS | \ + NINE_STATE_BLEND_COLOR | \ + NINE_STATE_STENCIL_REF | \ + NINE_STATE_SAMPLE_MASK) + +#define NINE_STATE_FREQ_GROUP_1 ~NINE_STATE_FREQ_GROUP_0 + +#define NINE_STATE_SHADER_VARIANT_GROUP \ + (NINE_STATE_TEXTURE | \ + NINE_STATE_VS | \ + NINE_STATE_PS) + +boolean +nine_update_state(struct NineDevice9 *device, uint32_t mask) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + uint32_t group; + + DBG("changed state groups: %x | %x\n", + state->changed.group & NINE_STATE_FREQ_GROUP_0, + state->changed.group & NINE_STATE_FREQ_GROUP_1); + + /* NOTE: We may want to use the cso cache for everything, or let + * NineDevice9.RestoreNonCSOState actually set the states, then we wouldn't + * have to care about state being clobbered here and could merge this back + * into update_textures. Except, we also need to re-validate textures that + * may be dirty anyway, even if no texture bindings changed. + */ + validate_textures(device); /* may clobber state */ + + /* ff_update may change VS/PS dirty bits */ + if ((mask & NINE_STATE_FF) && unlikely(!state->vs || !state->ps)) + nine_ff_update(device); + group = state->changed.group & mask; + + if (group & NINE_STATE_SHADER_VARIANT_GROUP) + group |= update_shader_variant_keys(device); + + if (group & NINE_STATE_FREQ_GROUP_0) { + if (group & NINE_STATE_FB) + group = update_framebuffer(device) & mask; + if (group & NINE_STATE_VIEWPORT) + update_viewport(device); + if (group & NINE_STATE_SCISSOR) + update_scissor(device); + + if (group & NINE_STATE_DSA) + update_dsa(device); + if (group & NINE_STATE_BLEND) + update_blend(device); + + if (group & NINE_STATE_VS) + group |= update_vs(device); + + if (group & NINE_STATE_RASTERIZER) + update_rasterizer(device); + + if (group & NINE_STATE_PS) + group |= update_ps(device); + + if (group & NINE_STATE_BLEND_COLOR) { + struct pipe_blend_color color; + d3dcolor_to_rgba(&color.color[0], state->rs[D3DRS_BLENDFACTOR]); + pipe->set_blend_color(pipe, &color); + } + if (group & NINE_STATE_SAMPLE_MASK) { + pipe->set_sample_mask(pipe, state->rs[D3DRS_MULTISAMPLEMASK]); + } + if (group & NINE_STATE_STENCIL_REF) { + struct pipe_stencil_ref ref; + ref.ref_value[0] = state->rs[D3DRS_STENCILREF]; + ref.ref_value[1] = ref.ref_value[0]; + pipe->set_stencil_ref(pipe, &ref); + } + } + + if (state->changed.ucp) + pipe->set_clip_state(pipe, &state->clip); + + if (group & (NINE_STATE_FREQ_GROUP_1 | NINE_STATE_VS)) { + if (group & (NINE_STATE_TEXTURE | NINE_STATE_SAMPLER)) + update_textures_and_samplers(device); + + if (group & NINE_STATE_IDXBUF) + update_index_buffer(device); + + if ((group & (NINE_STATE_VDECL | NINE_STATE_VS)) || + state->changed.stream_freq & ~1) + update_vertex_elements(device); + + if (device->prefer_user_constbuf) { + if ((group & (NINE_STATE_VS_CONST | NINE_STATE_VS)) && state->vs) + update_vs_constants_userbuf(device); + if ((group & (NINE_STATE_PS_CONST | NINE_STATE_PS)) && state->ps) + update_ps_constants_userbuf(device); + } else { + if ((group & NINE_STATE_VS_CONST) && state->vs) + update_constants(device, PIPE_SHADER_VERTEX); + if ((group & NINE_STATE_PS_CONST) && state->ps) + update_constants(device, PIPE_SHADER_FRAGMENT); + } + } + if (state->changed.vtxbuf) + update_vertex_buffers(device); + + device->state.changed.group &= ~mask | + (NINE_STATE_FF | NINE_STATE_VS_CONST | NINE_STATE_PS_CONST); + + DBG("finished\n"); + + return TRUE; +} + + +static const DWORD nine_render_state_defaults[NINED3DRS_LAST + 1] = +{ + /* [D3DRS_ZENABLE] = D3DZB_TRUE; wine: auto_depth_stencil */ + [D3DRS_ZENABLE] = D3DZB_FALSE, + [D3DRS_FILLMODE] = D3DFILL_SOLID, + [D3DRS_SHADEMODE] = D3DSHADE_GOURAUD, +/* [D3DRS_LINEPATTERN] = 0x00000000, */ + [D3DRS_ZWRITEENABLE] = TRUE, + [D3DRS_ALPHATESTENABLE] = FALSE, + [D3DRS_LASTPIXEL] = TRUE, + [D3DRS_SRCBLEND] = D3DBLEND_ONE, + [D3DRS_DESTBLEND] = D3DBLEND_ZERO, + [D3DRS_CULLMODE] = D3DCULL_CCW, + [D3DRS_ZFUNC] = D3DCMP_LESSEQUAL, + [D3DRS_ALPHAFUNC] = D3DCMP_ALWAYS, + [D3DRS_ALPHAREF] = 0, + [D3DRS_DITHERENABLE] = FALSE, + [D3DRS_ALPHABLENDENABLE] = FALSE, + [D3DRS_FOGENABLE] = FALSE, + [D3DRS_SPECULARENABLE] = FALSE, +/* [D3DRS_ZVISIBLE] = 0, */ + [D3DRS_FOGCOLOR] = 0, + [D3DRS_FOGTABLEMODE] = D3DFOG_NONE, + [D3DRS_FOGSTART] = 0x00000000, + [D3DRS_FOGEND] = 0x3F800000, + [D3DRS_FOGDENSITY] = 0x3F800000, +/* [D3DRS_EDGEANTIALIAS] = FALSE, */ + [D3DRS_RANGEFOGENABLE] = FALSE, + [D3DRS_STENCILENABLE] = FALSE, + [D3DRS_STENCILFAIL] = D3DSTENCILOP_KEEP, + [D3DRS_STENCILZFAIL] = D3DSTENCILOP_KEEP, + [D3DRS_STENCILPASS] = D3DSTENCILOP_KEEP, + [D3DRS_STENCILREF] = 0, + [D3DRS_STENCILMASK] = 0xFFFFFFFF, + [D3DRS_STENCILFUNC] = D3DCMP_ALWAYS, + [D3DRS_STENCILWRITEMASK] = 0xFFFFFFFF, + [D3DRS_TEXTUREFACTOR] = 0xFFFFFFFF, + [D3DRS_WRAP0] = 0, + [D3DRS_WRAP1] = 0, + [D3DRS_WRAP2] = 0, + [D3DRS_WRAP3] = 0, + [D3DRS_WRAP4] = 0, + [D3DRS_WRAP5] = 0, + [D3DRS_WRAP6] = 0, + [D3DRS_WRAP7] = 0, + [D3DRS_CLIPPING] = TRUE, + [D3DRS_LIGHTING] = TRUE, + [D3DRS_AMBIENT] = 0, + [D3DRS_FOGVERTEXMODE] = D3DFOG_NONE, + [D3DRS_COLORVERTEX] = TRUE, + [D3DRS_LOCALVIEWER] = TRUE, + [D3DRS_NORMALIZENORMALS] = FALSE, + [D3DRS_DIFFUSEMATERIALSOURCE] = D3DMCS_COLOR1, + [D3DRS_SPECULARMATERIALSOURCE] = D3DMCS_COLOR2, + [D3DRS_AMBIENTMATERIALSOURCE] = D3DMCS_MATERIAL, + [D3DRS_EMISSIVEMATERIALSOURCE] = D3DMCS_MATERIAL, + [D3DRS_VERTEXBLEND] = D3DVBF_DISABLE, + [D3DRS_CLIPPLANEENABLE] = 0, +/* [D3DRS_SOFTWAREVERTEXPROCESSING] = FALSE, */ + [D3DRS_POINTSIZE] = 0x3F800000, + [D3DRS_POINTSIZE_MIN] = 0x3F800000, + [D3DRS_POINTSPRITEENABLE] = FALSE, + [D3DRS_POINTSCALEENABLE] = FALSE, + [D3DRS_POINTSCALE_A] = 0x3F800000, + [D3DRS_POINTSCALE_B] = 0x00000000, + [D3DRS_POINTSCALE_C] = 0x00000000, + [D3DRS_MULTISAMPLEANTIALIAS] = TRUE, + [D3DRS_MULTISAMPLEMASK] = 0xFFFFFFFF, + [D3DRS_PATCHEDGESTYLE] = D3DPATCHEDGE_DISCRETE, +/* [D3DRS_PATCHSEGMENTS] = 0x3F800000, */ + [D3DRS_DEBUGMONITORTOKEN] = 0xDEADCAFE, + [D3DRS_POINTSIZE_MAX] = 0x3F800000, /* depends on cap */ + [D3DRS_INDEXEDVERTEXBLENDENABLE] = FALSE, + [D3DRS_COLORWRITEENABLE] = 0x0000000f, + [D3DRS_TWEENFACTOR] = 0x00000000, + [D3DRS_BLENDOP] = D3DBLENDOP_ADD, + [D3DRS_POSITIONDEGREE] = D3DDEGREE_CUBIC, + [D3DRS_NORMALDEGREE] = D3DDEGREE_LINEAR, + [D3DRS_SCISSORTESTENABLE] = FALSE, + [D3DRS_SLOPESCALEDEPTHBIAS] = 0, + [D3DRS_MINTESSELLATIONLEVEL] = 0x3F800000, + [D3DRS_MAXTESSELLATIONLEVEL] = 0x3F800000, + [D3DRS_ANTIALIASEDLINEENABLE] = FALSE, + [D3DRS_ADAPTIVETESS_X] = 0x00000000, + [D3DRS_ADAPTIVETESS_Y] = 0x00000000, + [D3DRS_ADAPTIVETESS_Z] = 0x3F800000, + [D3DRS_ADAPTIVETESS_W] = 0x00000000, + [D3DRS_ENABLEADAPTIVETESSELLATION] = FALSE, + [D3DRS_TWOSIDEDSTENCILMODE] = FALSE, + [D3DRS_CCW_STENCILFAIL] = D3DSTENCILOP_KEEP, + [D3DRS_CCW_STENCILZFAIL] = D3DSTENCILOP_KEEP, + [D3DRS_CCW_STENCILPASS] = D3DSTENCILOP_KEEP, + [D3DRS_CCW_STENCILFUNC] = D3DCMP_ALWAYS, + [D3DRS_COLORWRITEENABLE1] = 0x0000000F, + [D3DRS_COLORWRITEENABLE2] = 0x0000000F, + [D3DRS_COLORWRITEENABLE3] = 0x0000000F, + [D3DRS_BLENDFACTOR] = 0xFFFFFFFF, + [D3DRS_SRGBWRITEENABLE] = 0, + [D3DRS_DEPTHBIAS] = 0, + [D3DRS_WRAP8] = 0, + [D3DRS_WRAP9] = 0, + [D3DRS_WRAP10] = 0, + [D3DRS_WRAP11] = 0, + [D3DRS_WRAP12] = 0, + [D3DRS_WRAP13] = 0, + [D3DRS_WRAP14] = 0, + [D3DRS_WRAP15] = 0, + [D3DRS_SEPARATEALPHABLENDENABLE] = FALSE, + [D3DRS_SRCBLENDALPHA] = D3DBLEND_ONE, + [D3DRS_DESTBLENDALPHA] = D3DBLEND_ZERO, + [D3DRS_BLENDOPALPHA] = D3DBLENDOP_ADD, + [NINED3DRS_VSPOINTSIZE] = FALSE, + [NINED3DRS_RTMASK] = 0xf +}; +static const DWORD nine_tex_stage_state_defaults[NINED3DTSS_LAST + 1] = +{ + [D3DTSS_COLOROP] = D3DTOP_DISABLE, + [D3DTSS_ALPHAOP] = D3DTOP_DISABLE, + [D3DTSS_COLORARG1] = D3DTA_TEXTURE, + [D3DTSS_COLORARG2] = D3DTA_CURRENT, + [D3DTSS_COLORARG0] = D3DTA_CURRENT, + [D3DTSS_ALPHAARG1] = D3DTA_TEXTURE, + [D3DTSS_ALPHAARG2] = D3DTA_CURRENT, + [D3DTSS_ALPHAARG0] = D3DTA_CURRENT, + [D3DTSS_RESULTARG] = D3DTA_CURRENT, + [D3DTSS_BUMPENVMAT00] = 0, + [D3DTSS_BUMPENVMAT01] = 0, + [D3DTSS_BUMPENVMAT10] = 0, + [D3DTSS_BUMPENVMAT11] = 0, + [D3DTSS_BUMPENVLSCALE] = 0, + [D3DTSS_BUMPENVLOFFSET] = 0, + [D3DTSS_TEXCOORDINDEX] = 0, + [D3DTSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE, +}; +static const DWORD nine_samp_state_defaults[NINED3DSAMP_LAST + 1] = +{ + [D3DSAMP_ADDRESSU] = D3DTADDRESS_WRAP, + [D3DSAMP_ADDRESSV] = D3DTADDRESS_WRAP, + [D3DSAMP_ADDRESSW] = D3DTADDRESS_WRAP, + [D3DSAMP_BORDERCOLOR] = 0, + [D3DSAMP_MAGFILTER] = D3DTEXF_POINT, + [D3DSAMP_MINFILTER] = D3DTEXF_POINT, + [D3DSAMP_MIPFILTER] = D3DTEXF_NONE, + [D3DSAMP_MIPMAPLODBIAS] = 0, + [D3DSAMP_MAXMIPLEVEL] = 0, + [D3DSAMP_MAXANISOTROPY] = 1, + [D3DSAMP_SRGBTEXTURE] = 0, + [D3DSAMP_ELEMENTINDEX] = 0, + [D3DSAMP_DMAPOFFSET] = 0, + [NINED3DSAMP_MINLOD] = 0, + [NINED3DSAMP_SHADOW] = 0 +}; +void +nine_state_set_defaults(struct nine_state *state, const D3DCAPS9 *caps, + boolean is_reset) +{ + unsigned s; + + /* Initialize defaults. + */ + memcpy(state->rs, nine_render_state_defaults, sizeof(state->rs)); + + for (s = 0; s < Elements(state->ff.tex_stage); ++s) { + memcpy(&state->ff.tex_stage[s], nine_tex_stage_state_defaults, + sizeof(state->ff.tex_stage[s])); + state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] = s; + } + state->ff.tex_stage[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; + state->ff.tex_stage[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; + + for (s = 0; s < Elements(state->samp); ++s) { + memcpy(&state->samp[s], nine_samp_state_defaults, + sizeof(state->samp[s])); + } + + if (state->vs_const_f) + memset(state->vs_const_f, 0, NINE_MAX_CONST_F * 4 * sizeof(float)); + if (state->ps_const_f) + memset(state->ps_const_f, 0, NINE_MAX_CONST_F * 4 * sizeof(float)); + + /* Cap dependent initial state: + */ + state->rs[D3DRS_POINTSIZE_MAX] = fui(caps->MaxPointSize); + + /* Set changed flags to initialize driver. + */ + state->changed.group = NINE_STATE_ALL; + + state->ff.changed.transform[0] = ~0; + state->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32); + + if (!is_reset) { + state->viewport.MinZ = 0.0f; + state->viewport.MaxZ = 1.0f; + } + + for (s = 0; s < Elements(state->changed.sampler); ++s) + state->changed.sampler[s] = ~0; +} + +void +nine_state_clear(struct nine_state *state, const boolean device) +{ + unsigned i; + + for (i = 0; i < Elements(state->rt); ++i) + nine_bind(&state->rt[i], NULL); + nine_bind(&state->ds, NULL); + nine_bind(&state->vs, NULL); + nine_bind(&state->ps, NULL); + nine_bind(&state->vdecl, NULL); + for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) + nine_bind(&state->stream[i], NULL); + nine_bind(&state->idxbuf, NULL); + for (i = 0; i < NINE_MAX_SAMPLERS; ++i) { + if (device && + state->texture[i] && + --state->texture[i]->bind_count == 0) + list_delinit(&state->texture[i]->list); + nine_bind(&state->texture[i], NULL); + } +} + +/* +static const DWORD nine_render_states_pixel[] = +{ + D3DRS_ALPHABLENDENABLE, + D3DRS_ALPHAFUNC, + D3DRS_ALPHAREF, + D3DRS_ALPHATESTENABLE, + D3DRS_ANTIALIASEDLINEENABLE, + D3DRS_BLENDFACTOR, + D3DRS_BLENDOP, + D3DRS_BLENDOPALPHA, + D3DRS_CCW_STENCILFAIL, + D3DRS_CCW_STENCILPASS, + D3DRS_CCW_STENCILZFAIL, + D3DRS_COLORWRITEENABLE, + D3DRS_COLORWRITEENABLE1, + D3DRS_COLORWRITEENABLE2, + D3DRS_COLORWRITEENABLE3, + D3DRS_DEPTHBIAS, + D3DRS_DESTBLEND, + D3DRS_DESTBLENDALPHA, + D3DRS_DITHERENABLE, + D3DRS_FILLMODE, + D3DRS_FOGDENSITY, + D3DRS_FOGEND, + D3DRS_FOGSTART, + D3DRS_LASTPIXEL, + D3DRS_SCISSORTESTENABLE, + D3DRS_SEPARATEALPHABLENDENABLE, + D3DRS_SHADEMODE, + D3DRS_SLOPESCALEDEPTHBIAS, + D3DRS_SRCBLEND, + D3DRS_SRCBLENDALPHA, + D3DRS_SRGBWRITEENABLE, + D3DRS_STENCILENABLE, + D3DRS_STENCILFAIL, + D3DRS_STENCILFUNC, + D3DRS_STENCILMASK, + D3DRS_STENCILPASS, + D3DRS_STENCILREF, + D3DRS_STENCILWRITEMASK, + D3DRS_STENCILZFAIL, + D3DRS_TEXTUREFACTOR, + D3DRS_TWOSIDEDSTENCILMODE, + D3DRS_WRAP0, + D3DRS_WRAP1, + D3DRS_WRAP10, + D3DRS_WRAP11, + D3DRS_WRAP12, + D3DRS_WRAP13, + D3DRS_WRAP14, + D3DRS_WRAP15, + D3DRS_WRAP2, + D3DRS_WRAP3, + D3DRS_WRAP4, + D3DRS_WRAP5, + D3DRS_WRAP6, + D3DRS_WRAP7, + D3DRS_WRAP8, + D3DRS_WRAP9, + D3DRS_ZENABLE, + D3DRS_ZFUNC, + D3DRS_ZWRITEENABLE +}; +*/ +const uint32_t nine_render_states_pixel[(NINED3DRS_LAST + 31) / 32] = +{ + 0x0f99c380, 0x1ff00070, 0x00000000, 0x00000000, + 0x000000ff, 0xde01c900, 0x0003ffcf +}; + +/* +static const DWORD nine_render_states_vertex[] = +{ + D3DRS_ADAPTIVETESS_W, + D3DRS_ADAPTIVETESS_X, + D3DRS_ADAPTIVETESS_Y, + D3DRS_ADAPTIVETESS_Z, + D3DRS_AMBIENT, + D3DRS_AMBIENTMATERIALSOURCE, + D3DRS_CLIPPING, + D3DRS_CLIPPLANEENABLE, + D3DRS_COLORVERTEX, + D3DRS_CULLMODE, + D3DRS_DIFFUSEMATERIALSOURCE, + D3DRS_EMISSIVEMATERIALSOURCE, + D3DRS_ENABLEADAPTIVETESSELLATION, + D3DRS_FOGCOLOR, + D3DRS_FOGDENSITY, + D3DRS_FOGENABLE, + D3DRS_FOGEND, + D3DRS_FOGSTART, + D3DRS_FOGTABLEMODE, + D3DRS_FOGVERTEXMODE, + D3DRS_INDEXEDVERTEXBLENDENABLE, + D3DRS_LIGHTING, + D3DRS_LOCALVIEWER, + D3DRS_MAXTESSELLATIONLEVEL, + D3DRS_MINTESSELLATIONLEVEL, + D3DRS_MULTISAMPLEANTIALIAS, + D3DRS_MULTISAMPLEMASK, + D3DRS_NORMALDEGREE, + D3DRS_NORMALIZENORMALS, + D3DRS_PATCHEDGESTYLE, + D3DRS_POINTSCALE_A, + D3DRS_POINTSCALE_B, + D3DRS_POINTSCALE_C, + D3DRS_POINTSCALEENABLE, + D3DRS_POINTSIZE, + D3DRS_POINTSIZE_MAX, + D3DRS_POINTSIZE_MIN, + D3DRS_POINTSPRITEENABLE, + D3DRS_POSITIONDEGREE, + D3DRS_RANGEFOGENABLE, + D3DRS_SHADEMODE, + D3DRS_SPECULARENABLE, + D3DRS_SPECULARMATERIALSOURCE, + D3DRS_TWEENFACTOR, + D3DRS_VERTEXBLEND +}; +*/ +const uint32_t nine_render_states_vertex[(NINED3DRS_LAST + 31) / 32] = +{ + 0x30400200, 0x0001007c, 0x00000000, 0x00000000, + 0xfd9efb00, 0x01fc34cf, 0x00000000 +}; + +/* TODO: put in the right values */ +const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] = +{ + [D3DRS_ZENABLE] = NINE_STATE_DSA, + [D3DRS_FILLMODE] = NINE_STATE_RASTERIZER, + [D3DRS_SHADEMODE] = NINE_STATE_RASTERIZER, + [D3DRS_ZWRITEENABLE] = NINE_STATE_DSA, + [D3DRS_ALPHATESTENABLE] = NINE_STATE_DSA, + [D3DRS_LASTPIXEL] = NINE_STATE_RASTERIZER, + [D3DRS_SRCBLEND] = NINE_STATE_BLEND, + [D3DRS_DESTBLEND] = NINE_STATE_BLEND, + [D3DRS_CULLMODE] = NINE_STATE_RASTERIZER, + [D3DRS_ZFUNC] = NINE_STATE_DSA, + [D3DRS_ALPHAREF] = NINE_STATE_DSA, + [D3DRS_ALPHAFUNC] = NINE_STATE_DSA, + [D3DRS_DITHERENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_ALPHABLENDENABLE] = NINE_STATE_BLEND, + [D3DRS_FOGENABLE] = NINE_STATE_FF_OTHER, + [D3DRS_SPECULARENABLE] = NINE_STATE_FF_LIGHTING, + [D3DRS_FOGCOLOR] = NINE_STATE_FF_OTHER, + [D3DRS_FOGTABLEMODE] = NINE_STATE_FF_OTHER, + [D3DRS_FOGSTART] = NINE_STATE_FF_OTHER, + [D3DRS_FOGEND] = NINE_STATE_FF_OTHER, + [D3DRS_FOGDENSITY] = NINE_STATE_FF_OTHER, + [D3DRS_RANGEFOGENABLE] = NINE_STATE_FF_OTHER, + [D3DRS_STENCILENABLE] = NINE_STATE_DSA, + [D3DRS_STENCILFAIL] = NINE_STATE_DSA, + [D3DRS_STENCILZFAIL] = NINE_STATE_DSA, + [D3DRS_STENCILPASS] = NINE_STATE_DSA, + [D3DRS_STENCILFUNC] = NINE_STATE_DSA, + [D3DRS_STENCILREF] = NINE_STATE_STENCIL_REF, + [D3DRS_STENCILMASK] = NINE_STATE_DSA, + [D3DRS_STENCILWRITEMASK] = NINE_STATE_DSA, + [D3DRS_TEXTUREFACTOR] = NINE_STATE_FF_PSSTAGES, + [D3DRS_WRAP0] = NINE_STATE_UNHANDLED, /* cylindrical wrap is crazy */ + [D3DRS_WRAP1] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP2] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP3] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP4] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP5] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP6] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP7] = NINE_STATE_UNHANDLED, + [D3DRS_CLIPPING] = 0, /* software vertex processing only */ + [D3DRS_LIGHTING] = NINE_STATE_FF_LIGHTING, + [D3DRS_AMBIENT] = NINE_STATE_FF_LIGHTING | NINE_STATE_FF_MATERIAL, + [D3DRS_FOGVERTEXMODE] = NINE_STATE_FF_OTHER, + [D3DRS_COLORVERTEX] = NINE_STATE_FF_LIGHTING, + [D3DRS_LOCALVIEWER] = NINE_STATE_FF_LIGHTING, + [D3DRS_NORMALIZENORMALS] = NINE_STATE_FF_OTHER, + [D3DRS_DIFFUSEMATERIALSOURCE] = NINE_STATE_FF_LIGHTING, + [D3DRS_SPECULARMATERIALSOURCE] = NINE_STATE_FF_LIGHTING, + [D3DRS_AMBIENTMATERIALSOURCE] = NINE_STATE_FF_LIGHTING, + [D3DRS_EMISSIVEMATERIALSOURCE] = NINE_STATE_FF_LIGHTING, + [D3DRS_VERTEXBLEND] = NINE_STATE_FF_OTHER, + [D3DRS_CLIPPLANEENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_POINTSIZE] = NINE_STATE_RASTERIZER, + [D3DRS_POINTSIZE_MIN] = NINE_STATE_MISC_CONST, + [D3DRS_POINTSPRITEENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_POINTSCALEENABLE] = NINE_STATE_FF_OTHER, + [D3DRS_POINTSCALE_A] = NINE_STATE_FF_OTHER, + [D3DRS_POINTSCALE_B] = NINE_STATE_FF_OTHER, + [D3DRS_POINTSCALE_C] = NINE_STATE_FF_OTHER, + [D3DRS_MULTISAMPLEANTIALIAS] = NINE_STATE_RASTERIZER, + [D3DRS_MULTISAMPLEMASK] = NINE_STATE_SAMPLE_MASK, + [D3DRS_PATCHEDGESTYLE] = NINE_STATE_UNHANDLED, + [D3DRS_DEBUGMONITORTOKEN] = NINE_STATE_UNHANDLED, + [D3DRS_POINTSIZE_MAX] = NINE_STATE_MISC_CONST, + [D3DRS_INDEXEDVERTEXBLENDENABLE] = NINE_STATE_FF_OTHER, + [D3DRS_COLORWRITEENABLE] = NINE_STATE_BLEND, + [D3DRS_TWEENFACTOR] = NINE_STATE_FF_OTHER, + [D3DRS_BLENDOP] = NINE_STATE_BLEND, + [D3DRS_POSITIONDEGREE] = NINE_STATE_UNHANDLED, + [D3DRS_NORMALDEGREE] = NINE_STATE_UNHANDLED, + [D3DRS_SCISSORTESTENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_SLOPESCALEDEPTHBIAS] = NINE_STATE_RASTERIZER, + [D3DRS_ANTIALIASEDLINEENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_MINTESSELLATIONLEVEL] = NINE_STATE_UNHANDLED, + [D3DRS_MAXTESSELLATIONLEVEL] = NINE_STATE_UNHANDLED, + [D3DRS_ADAPTIVETESS_X] = NINE_STATE_UNHANDLED, + [D3DRS_ADAPTIVETESS_Y] = NINE_STATE_UNHANDLED, + [D3DRS_ADAPTIVETESS_Z] = NINE_STATE_UNHANDLED, + [D3DRS_ADAPTIVETESS_W] = NINE_STATE_UNHANDLED, + [D3DRS_ENABLEADAPTIVETESSELLATION] = NINE_STATE_UNHANDLED, + [D3DRS_TWOSIDEDSTENCILMODE] = NINE_STATE_DSA, + [D3DRS_CCW_STENCILFAIL] = NINE_STATE_DSA, + [D3DRS_CCW_STENCILZFAIL] = NINE_STATE_DSA, + [D3DRS_CCW_STENCILPASS] = NINE_STATE_DSA, + [D3DRS_CCW_STENCILFUNC] = NINE_STATE_DSA, + [D3DRS_COLORWRITEENABLE1] = NINE_STATE_BLEND, + [D3DRS_COLORWRITEENABLE2] = NINE_STATE_BLEND, + [D3DRS_COLORWRITEENABLE3] = NINE_STATE_BLEND, + [D3DRS_BLENDFACTOR] = NINE_STATE_BLEND_COLOR, + [D3DRS_SRGBWRITEENABLE] = NINE_STATE_FB, + [D3DRS_DEPTHBIAS] = NINE_STATE_RASTERIZER, + [D3DRS_WRAP8] = NINE_STATE_UNHANDLED, /* cylwrap has to be done via GP */ + [D3DRS_WRAP9] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP10] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP11] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP12] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP13] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP14] = NINE_STATE_UNHANDLED, + [D3DRS_WRAP15] = NINE_STATE_UNHANDLED, + [D3DRS_SEPARATEALPHABLENDENABLE] = NINE_STATE_BLEND, + [D3DRS_SRCBLENDALPHA] = NINE_STATE_BLEND, + [D3DRS_DESTBLENDALPHA] = NINE_STATE_BLEND, + [D3DRS_BLENDOPALPHA] = NINE_STATE_BLEND +}; + +D3DMATRIX * +nine_state_access_transform(struct nine_state *state, D3DTRANSFORMSTATETYPE t, + boolean alloc) +{ + static D3DMATRIX Identity = { .m[0] = { 1, 0, 0, 0 }, + .m[1] = { 0, 1, 0, 0 }, + .m[2] = { 0, 0, 1, 0 }, + .m[3] = { 0, 0, 0, 1 } }; + unsigned index; + + switch (t) { + case D3DTS_VIEW: index = 0; break; + case D3DTS_PROJECTION: index = 1; break; + case D3DTS_TEXTURE0: index = 2; break; + case D3DTS_TEXTURE1: index = 3; break; + case D3DTS_TEXTURE2: index = 4; break; + case D3DTS_TEXTURE3: index = 5; break; + case D3DTS_TEXTURE4: index = 6; break; + case D3DTS_TEXTURE5: index = 7; break; + case D3DTS_TEXTURE6: index = 8; break; + case D3DTS_TEXTURE7: index = 9; break; + default: + if (!(t >= D3DTS_WORLDMATRIX(0) && t <= D3DTS_WORLDMATRIX(255))) + return NULL; + index = 10 + (t - D3DTS_WORLDMATRIX(0)); + break; + } + + if (index >= state->ff.num_transforms) { + unsigned N = index + 1; + unsigned n = state->ff.num_transforms; + + if (!alloc) + return &Identity; + state->ff.transform = REALLOC(state->ff.transform, + n * sizeof(D3DMATRIX), + N * sizeof(D3DMATRIX)); + for (; n < N; ++n) + state->ff.transform[n] = Identity; + state->ff.num_transforms = N; + } + return &state->ff.transform[index]; +} + +#define D3DRS_TO_STRING_CASE(n) case D3DRS_##n: return "D3DRS_"#n +const char *nine_d3drs_to_string(DWORD State) +{ + switch (State) { + D3DRS_TO_STRING_CASE(ZENABLE); + D3DRS_TO_STRING_CASE(FILLMODE); + D3DRS_TO_STRING_CASE(SHADEMODE); + D3DRS_TO_STRING_CASE(ZWRITEENABLE); + D3DRS_TO_STRING_CASE(ALPHATESTENABLE); + D3DRS_TO_STRING_CASE(LASTPIXEL); + D3DRS_TO_STRING_CASE(SRCBLEND); + D3DRS_TO_STRING_CASE(DESTBLEND); + D3DRS_TO_STRING_CASE(CULLMODE); + D3DRS_TO_STRING_CASE(ZFUNC); + D3DRS_TO_STRING_CASE(ALPHAREF); + D3DRS_TO_STRING_CASE(ALPHAFUNC); + D3DRS_TO_STRING_CASE(DITHERENABLE); + D3DRS_TO_STRING_CASE(ALPHABLENDENABLE); + D3DRS_TO_STRING_CASE(FOGENABLE); + D3DRS_TO_STRING_CASE(SPECULARENABLE); + D3DRS_TO_STRING_CASE(FOGCOLOR); + D3DRS_TO_STRING_CASE(FOGTABLEMODE); + D3DRS_TO_STRING_CASE(FOGSTART); + D3DRS_TO_STRING_CASE(FOGEND); + D3DRS_TO_STRING_CASE(FOGDENSITY); + D3DRS_TO_STRING_CASE(RANGEFOGENABLE); + D3DRS_TO_STRING_CASE(STENCILENABLE); + D3DRS_TO_STRING_CASE(STENCILFAIL); + D3DRS_TO_STRING_CASE(STENCILZFAIL); + D3DRS_TO_STRING_CASE(STENCILPASS); + D3DRS_TO_STRING_CASE(STENCILFUNC); + D3DRS_TO_STRING_CASE(STENCILREF); + D3DRS_TO_STRING_CASE(STENCILMASK); + D3DRS_TO_STRING_CASE(STENCILWRITEMASK); + D3DRS_TO_STRING_CASE(TEXTUREFACTOR); + D3DRS_TO_STRING_CASE(WRAP0); + D3DRS_TO_STRING_CASE(WRAP1); + D3DRS_TO_STRING_CASE(WRAP2); + D3DRS_TO_STRING_CASE(WRAP3); + D3DRS_TO_STRING_CASE(WRAP4); + D3DRS_TO_STRING_CASE(WRAP5); + D3DRS_TO_STRING_CASE(WRAP6); + D3DRS_TO_STRING_CASE(WRAP7); + D3DRS_TO_STRING_CASE(CLIPPING); + D3DRS_TO_STRING_CASE(LIGHTING); + D3DRS_TO_STRING_CASE(AMBIENT); + D3DRS_TO_STRING_CASE(FOGVERTEXMODE); + D3DRS_TO_STRING_CASE(COLORVERTEX); + D3DRS_TO_STRING_CASE(LOCALVIEWER); + D3DRS_TO_STRING_CASE(NORMALIZENORMALS); + D3DRS_TO_STRING_CASE(DIFFUSEMATERIALSOURCE); + D3DRS_TO_STRING_CASE(SPECULARMATERIALSOURCE); + D3DRS_TO_STRING_CASE(AMBIENTMATERIALSOURCE); + D3DRS_TO_STRING_CASE(EMISSIVEMATERIALSOURCE); + D3DRS_TO_STRING_CASE(VERTEXBLEND); + D3DRS_TO_STRING_CASE(CLIPPLANEENABLE); + D3DRS_TO_STRING_CASE(POINTSIZE); + D3DRS_TO_STRING_CASE(POINTSIZE_MIN); + D3DRS_TO_STRING_CASE(POINTSPRITEENABLE); + D3DRS_TO_STRING_CASE(POINTSCALEENABLE); + D3DRS_TO_STRING_CASE(POINTSCALE_A); + D3DRS_TO_STRING_CASE(POINTSCALE_B); + D3DRS_TO_STRING_CASE(POINTSCALE_C); + D3DRS_TO_STRING_CASE(MULTISAMPLEANTIALIAS); + D3DRS_TO_STRING_CASE(MULTISAMPLEMASK); + D3DRS_TO_STRING_CASE(PATCHEDGESTYLE); + D3DRS_TO_STRING_CASE(DEBUGMONITORTOKEN); + D3DRS_TO_STRING_CASE(POINTSIZE_MAX); + D3DRS_TO_STRING_CASE(INDEXEDVERTEXBLENDENABLE); + D3DRS_TO_STRING_CASE(COLORWRITEENABLE); + D3DRS_TO_STRING_CASE(TWEENFACTOR); + D3DRS_TO_STRING_CASE(BLENDOP); + D3DRS_TO_STRING_CASE(POSITIONDEGREE); + D3DRS_TO_STRING_CASE(NORMALDEGREE); + D3DRS_TO_STRING_CASE(SCISSORTESTENABLE); + D3DRS_TO_STRING_CASE(SLOPESCALEDEPTHBIAS); + D3DRS_TO_STRING_CASE(ANTIALIASEDLINEENABLE); + D3DRS_TO_STRING_CASE(MINTESSELLATIONLEVEL); + D3DRS_TO_STRING_CASE(MAXTESSELLATIONLEVEL); + D3DRS_TO_STRING_CASE(ADAPTIVETESS_X); + D3DRS_TO_STRING_CASE(ADAPTIVETESS_Y); + D3DRS_TO_STRING_CASE(ADAPTIVETESS_Z); + D3DRS_TO_STRING_CASE(ADAPTIVETESS_W); + D3DRS_TO_STRING_CASE(ENABLEADAPTIVETESSELLATION); + D3DRS_TO_STRING_CASE(TWOSIDEDSTENCILMODE); + D3DRS_TO_STRING_CASE(CCW_STENCILFAIL); + D3DRS_TO_STRING_CASE(CCW_STENCILZFAIL); + D3DRS_TO_STRING_CASE(CCW_STENCILPASS); + D3DRS_TO_STRING_CASE(CCW_STENCILFUNC); + D3DRS_TO_STRING_CASE(COLORWRITEENABLE1); + D3DRS_TO_STRING_CASE(COLORWRITEENABLE2); + D3DRS_TO_STRING_CASE(COLORWRITEENABLE3); + D3DRS_TO_STRING_CASE(BLENDFACTOR); + D3DRS_TO_STRING_CASE(SRGBWRITEENABLE); + D3DRS_TO_STRING_CASE(DEPTHBIAS); + D3DRS_TO_STRING_CASE(WRAP8); + D3DRS_TO_STRING_CASE(WRAP9); + D3DRS_TO_STRING_CASE(WRAP10); + D3DRS_TO_STRING_CASE(WRAP11); + D3DRS_TO_STRING_CASE(WRAP12); + D3DRS_TO_STRING_CASE(WRAP13); + D3DRS_TO_STRING_CASE(WRAP14); + D3DRS_TO_STRING_CASE(WRAP15); + D3DRS_TO_STRING_CASE(SEPARATEALPHABLENDENABLE); + D3DRS_TO_STRING_CASE(SRCBLENDALPHA); + D3DRS_TO_STRING_CASE(DESTBLENDALPHA); + D3DRS_TO_STRING_CASE(BLENDOPALPHA); + default: + return "(invalid)"; + } +} + diff --git a/src/gallium/state_trackers/nine/nine_state.h b/src/gallium/state_trackers/nine/nine_state.h new file mode 100644 index 00000000000..3e0162c9dfc --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_state.h @@ -0,0 +1,234 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_STATE_H_ +#define _NINE_STATE_H_ + +#include "d3d9.h" +#include "nine_defines.h" +#include "pipe/p_state.h" +#include "util/u_double_list.h" + +#define NINED3DSAMP_MINLOD (D3DSAMP_DMAPOFFSET + 1) +#define NINED3DSAMP_SHADOW (D3DSAMP_DMAPOFFSET + 2) + +#define NINED3DRS_VSPOINTSIZE (D3DRS_BLENDOPALPHA + 1) +#define NINED3DRS_RTMASK (D3DRS_BLENDOPALPHA + 2) +#define NINED3DRS_ZBIASSCALE (D3DRS_BLENDOPALPHA + 3) + +#define D3DRS_LAST D3DRS_BLENDOPALPHA +#define NINED3DRS_LAST NINED3DRS_ZBIASSCALE /* 212 */ +#define NINED3DSAMP_LAST NINED3DSAMP_SHADOW /* 15 */ +#define NINED3DTSS_LAST D3DTSS_CONSTANT +#define NINED3DTS_LAST D3DTS_WORLDMATRIX(255) + +#define D3DRS_COUNT (D3DRS_LAST + 1) +#define NINED3DRS_COUNT (NINED3DRS_LAST + 1) +#define NINED3DSAMP_COUNT (NINED3DSAMP_LAST + 1) +#define NINED3DTSS_COUNT (NINED3DTSS_LAST + 1) +#define NINED3DTS_COUNT (NINED3DTS_LAST + 1) + +#define NINE_STATE_FB (1 << 0) +#define NINE_STATE_VIEWPORT (1 << 1) +#define NINE_STATE_SCISSOR (1 << 2) +#define NINE_STATE_RASTERIZER (1 << 3) +#define NINE_STATE_BLEND (1 << 4) +#define NINE_STATE_DSA (1 << 5) +#define NINE_STATE_VS (1 << 6) +#define NINE_STATE_VS_CONST (1 << 7) +#define NINE_STATE_PS (1 << 8) +#define NINE_STATE_PS_CONST (1 << 9) +#define NINE_STATE_TEXTURE (1 << 10) +#define NINE_STATE_SAMPLER (1 << 11) +#define NINE_STATE_VDECL (1 << 12) +#define NINE_STATE_IDXBUF (1 << 13) +#define NINE_STATE_PRIM (1 << 14) +#define NINE_STATE_MATERIAL (1 << 15) +#define NINE_STATE_BLEND_COLOR (1 << 16) +#define NINE_STATE_STENCIL_REF (1 << 17) +#define NINE_STATE_SAMPLE_MASK (1 << 18) +#define NINE_STATE_MISC_CONST (1 << 19) +#define NINE_STATE_FF (0x1f << 20) +#define NINE_STATE_FF_VS (0x17 << 20) +#define NINE_STATE_FF_PS (0x18 << 20) +#define NINE_STATE_FF_LIGHTING (1 << 20) +#define NINE_STATE_FF_MATERIAL (1 << 21) +#define NINE_STATE_FF_VSTRANSF (1 << 22) +#define NINE_STATE_FF_PSSTAGES (1 << 23) +#define NINE_STATE_FF_OTHER (1 << 24) +#define NINE_STATE_ALL 0x1ffffff +#define NINE_STATE_UNHANDLED (1 << 25) + + +#define NINE_MAX_SIMULTANEOUS_RENDERTARGETS 4 +#define NINE_MAX_CONST_F 256 +#define NINE_MAX_CONST_I 16 +#define NINE_MAX_CONST_B 16 +#define NINE_MAX_CONST_ALL 276 /* B consts count only 1/4 th */ + +#define NINE_CONST_I_BASE(nconstf) \ + ((nconstf) * 4 * sizeof(float)) +#define NINE_CONST_B_BASE(nconstf) \ + ((nconstf) * 4 * sizeof(float) + \ + NINE_MAX_CONST_I * 4 * sizeof(int)) + +#define NINE_CONSTBUF_SIZE(nconstf) \ + ((nconstf) * 4 * sizeof(float) + \ + NINE_MAX_CONST_I * 4 * sizeof(int) + \ + NINE_MAX_CONST_B * 1 * sizeof(float)) + + +#define NINE_MAX_LIGHTS 65536 +#define NINE_MAX_LIGHTS_ACTIVE 8 + +#define NINED3DLIGHT_INVALID (D3DLIGHT_DIRECTIONAL + 1) + +#define NINE_MAX_SAMPLERS_PS 16 +#define NINE_MAX_SAMPLERS_VS 4 +#define NINE_MAX_SAMPLERS 21 /* PS + DMAP + VS */ +#define NINE_SAMPLER_PS(s) ( 0 + (s)) +#define NINE_SAMPLER_DMAP 16 +#define NINE_SAMPLER_VS(s) (17 + (s)) +#define NINE_PS_SAMPLERS_MASK 0x00ffff +#define NINE_VS_SAMPLERS_MASK 0x1e0000 + +struct nine_state +{ + struct { + uint32_t group; + uint32_t rs[(NINED3DRS_COUNT + 31) / 32]; + uint32_t vtxbuf; + uint32_t stream_freq; + uint32_t texture; + uint16_t sampler[NINE_MAX_SAMPLERS]; + struct nine_range *vs_const_f; + struct nine_range *ps_const_f; + uint16_t vs_const_i; /* NINE_MAX_CONST_I == 16 */ + uint16_t ps_const_i; + uint16_t vs_const_b; /* NINE_MAX_CONST_B == 16 */ + uint16_t ps_const_b; + uint8_t ucp; + } changed; + + struct NineSurface9 *rt[NINE_MAX_SIMULTANEOUS_RENDERTARGETS]; + struct NineSurface9 *ds; + + D3DVIEWPORT9 viewport; + + struct pipe_scissor_state scissor; + + /* NOTE: vs, ps will be NULL for FF and are set in device->ff.vs,ps instead + * (XXX: or is it better to reference FF shaders here, too ?) + * NOTE: const_f contains extra space for const_i,b to use as user constbuf + */ + struct NineVertexShader9 *vs; + float *vs_const_f; + int vs_const_i[NINE_MAX_CONST_I][4]; + BOOL vs_const_b[NINE_MAX_CONST_B]; + uint32_t vs_key; + + struct NinePixelShader9 *ps; + float *ps_const_f; + int ps_const_i[NINE_MAX_CONST_I][4]; + BOOL ps_const_b[NINE_MAX_CONST_B]; + uint32_t ps_key; + + struct { + void *vs; + void *ps; + } cso; + + struct NineVertexDeclaration9 *vdecl; + + struct NineIndexBuffer9 *idxbuf; + struct NineVertexBuffer9 *stream[PIPE_MAX_ATTRIBS]; + struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS]; + UINT stream_freq[PIPE_MAX_ATTRIBS]; + uint32_t stream_instancedata_mask; /* derived from stream_freq */ + uint32_t stream_usage_mask; /* derived from VS and vdecl */ + + struct pipe_clip_state clip; + struct pipe_framebuffer_state fb; + uint8_t rt_mask; + + DWORD rs[NINED3DRS_COUNT]; + + struct NineBaseTexture9 *texture[NINE_MAX_SAMPLERS]; /* PS, DMAP, VS */ + + DWORD samp[NINE_MAX_SAMPLERS][NINED3DSAMP_COUNT]; + uint32_t samplers_shadow; + + struct { + struct { + uint32_t group; + uint32_t tex_stage[NINE_MAX_SAMPLERS][(NINED3DTSS_COUNT + 31) / 32]; + uint32_t transform[(NINED3DTS_COUNT + 31) / 32]; + } changed; + struct { + boolean vs_const; + boolean ps_const; + } clobber; + + D3DMATRIX *transform; /* access only via nine_state_access_transform */ + unsigned num_transforms; + + /* XXX: Do state blocks just change the set of active lights or do we + * have to store which lights have been disabled, too ? + */ + D3DLIGHT9 *light; + uint16_t active_light[NINE_MAX_LIGHTS_ACTIVE]; /* 8 */ + unsigned num_lights; + unsigned num_lights_active; + + D3DMATERIAL9 material; + + DWORD tex_stage[NINE_MAX_SAMPLERS][NINED3DTSS_COUNT]; + } ff; +}; + +/* map D3DRS -> NINE_STATE_x + */ +extern const uint32_t nine_render_state_group[NINED3DRS_COUNT]; + +/* for D3DSBT_PIXEL/VERTEX: + */ +extern const uint32_t nine_render_states_pixel[(NINED3DRS_COUNT + 31) / 32]; +extern const uint32_t nine_render_states_vertex[(NINED3DRS_COUNT + 31) / 32]; + +struct NineDevice9; + +boolean nine_update_state(struct NineDevice9 *, uint32_t group_mask); + +void nine_state_set_defaults(struct nine_state *, const D3DCAPS9 *, + boolean is_reset); +void nine_state_clear(struct nine_state *, const boolean device); + +/* If @alloc is FALSE, the return value may be a const identity matrix. + * Therefore, do not modify if you set alloc to FALSE ! + */ +D3DMATRIX * +nine_state_access_transform(struct nine_state *, D3DTRANSFORMSTATETYPE, + boolean alloc); + +const char *nine_d3drs_to_string(DWORD State); + +#endif /* _NINE_STATE_H_ */ diff --git a/src/gallium/state_trackers/nine/nineexoverlayextension.c b/src/gallium/state_trackers/nine/nineexoverlayextension.c new file mode 100644 index 00000000000..2253f8d9789 --- /dev/null +++ b/src/gallium/state_trackers/nine/nineexoverlayextension.c @@ -0,0 +1,46 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nineexoverlayextension.h" + +#define DBG_CHANNEL DBG_OVERLAYEXTENSION + +HRESULT WINAPI +Nine9ExOverlayExtension_CheckDeviceOverlayType( struct Nine9ExOverlayExtension *This, + UINT Adapter, + D3DDEVTYPE DevType, + UINT OverlayWidth, + UINT OverlayHeight, + D3DFORMAT OverlayFormat, + D3DDISPLAYMODEEX *pDisplayMode, + D3DDISPLAYROTATION DisplayRotation, + D3DOVERLAYCAPS *pOverlayCaps ) +{ + STUB(D3DERR_INVALIDCALL); +} + +IDirect3D9ExOverlayExtensionVtbl Nine9ExOverlayExtension_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)Nine9ExOverlayExtension_CheckDeviceOverlayType +}; diff --git a/src/gallium/state_trackers/nine/nineexoverlayextension.h b/src/gallium/state_trackers/nine/nineexoverlayextension.h new file mode 100644 index 00000000000..a16d690dc8c --- /dev/null +++ b/src/gallium/state_trackers/nine/nineexoverlayextension.h @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_NINEEXOVERLAYEXTENSION_H_ +#define _NINE_NINEEXOVERLAYEXTENSION_H_ + +#include "iunknown.h" + +struct Nine9ExOverlayExtension +{ + struct NineUnknown base; +}; +static INLINE struct Nine9ExOverlayExtension * +Nine9ExOverlayExtension( void *data ) +{ + return (struct Nine9ExOverlayExtension *)data; +} + +HRESULT WINAPI +Nine9ExOverlayExtension_CheckDeviceOverlayType( struct Nine9ExOverlayExtension *This, + UINT Adapter, + D3DDEVTYPE DevType, + UINT OverlayWidth, + UINT OverlayHeight, + D3DFORMAT OverlayFormat, + D3DDISPLAYMODEEX *pDisplayMode, + D3DDISPLAYROTATION DisplayRotation, + D3DOVERLAYCAPS *pOverlayCaps ); + +#endif /* _NINE_NINEEXOVERLAYEXTENSION_H_ */ diff --git a/src/gallium/state_trackers/nine/pixelshader9.c b/src/gallium/state_trackers/nine/pixelshader9.c new file mode 100644 index 00000000000..3d68274aa01 --- /dev/null +++ b/src/gallium/state_trackers/nine/pixelshader9.c @@ -0,0 +1,172 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_helpers.h" +#include "nine_shader.h" + +#include "pixelshader9.h" + +#include "device9.h" +#include "pipe/p_context.h" + +#define DBG_CHANNEL DBG_PIXELSHADER + +HRESULT +NinePixelShader9_ctor( struct NinePixelShader9 *This, + struct NineUnknownParams *pParams, + const DWORD *pFunction, void *cso ) +{ + struct NineDevice9 *device; + struct nine_shader_info info; + HRESULT hr; + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + if (cso) { + This->variant.cso = cso; + return D3D_OK; + } + device = This->base.device; + + info.type = PIPE_SHADER_FRAGMENT; + info.byte_code = pFunction; + info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16; + info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16; + info.sampler_mask_shadow = 0x0; + info.sampler_ps1xtypes = 0x0; + + hr = nine_translate_shader(device, &info); + if (FAILED(hr)) + return hr; + This->byte_code.version = info.version; + + This->byte_code.tokens = mem_dup(pFunction, info.byte_size); + if (!This->byte_code.tokens) + return E_OUTOFMEMORY; + This->byte_code.size = info.byte_size; + + This->variant.cso = info.cso; + This->sampler_mask = info.sampler_mask; + This->rt_mask = info.rt_mask; + This->const_used_size = info.const_used_size; + if (info.const_used_size == ~0) + This->const_used_size = NINE_CONSTBUF_SIZE(device->max_ps_const_f); + This->lconstf = info.lconstf; + + return D3D_OK; +} + +void +NinePixelShader9_dtor( struct NinePixelShader9 *This ) +{ + DBG("This=%p cso=%p\n", This, This->variant.cso); + + if (This->base.device) { + struct pipe_context *pipe = This->base.device->pipe; + struct nine_shader_variant *var = &This->variant; + do { + if (var->cso) { + if (This->base.device->state.cso.ps == var->cso) + pipe->bind_fs_state(pipe, NULL); + pipe->delete_fs_state(pipe, var->cso); + } + var = var->next; + } while (var); + } + nine_shader_variants_free(&This->variant); + + if (This->byte_code.tokens) + FREE((void *)This->byte_code.tokens); /* const_cast */ + + FREE(This->lconstf.data); + FREE(This->lconstf.ranges); + + NineUnknown_dtor(&This->base); +} + +HRESULT WINAPI +NinePixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + user_assert(pSizeOfData, D3DERR_INVALIDCALL); + + if (!pData) { + *pSizeOfData = This->byte_code.size; + return D3D_OK; + } + user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL); + + memcpy(pData, This->byte_code.tokens, This->byte_code.size); + + return D3D_OK; +} + +void * +NinePixelShader9_GetVariant( struct NinePixelShader9 *This, + uint32_t key ) +{ + void *cso = nine_shader_variant_get(&This->variant, key); + if (!cso) { + struct NineDevice9 *device = This->base.device; + struct nine_shader_info info; + HRESULT hr; + + info.type = PIPE_SHADER_FRAGMENT; + info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16; + info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16; + info.byte_code = This->byte_code.tokens; + info.sampler_mask_shadow = key & 0xffff; + info.sampler_ps1xtypes = key; + + hr = nine_translate_shader(This->base.device, &info); + if (FAILED(hr)) + return NULL; + nine_shader_variant_add(&This->variant, key, info.cso); + cso = info.cso; + } + return cso; +} + +IDirect3DPixelShader9Vtbl NinePixelShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, + (void *)NinePixelShader9_GetFunction +}; + +static const GUID *NinePixelShader9_IIDs[] = { + &IID_IDirect3DPixelShader9, + &IID_IUnknown, + NULL +}; + +HRESULT +NinePixelShader9_new( struct NineDevice9 *pDevice, + struct NinePixelShader9 **ppOut, + const DWORD *pFunction, void *cso ) +{ + NINE_DEVICE_CHILD_NEW(PixelShader9, ppOut, pDevice, pFunction, cso); +} diff --git a/src/gallium/state_trackers/nine/pixelshader9.h b/src/gallium/state_trackers/nine/pixelshader9.h new file mode 100644 index 00000000000..5e00b46e0c5 --- /dev/null +++ b/src/gallium/state_trackers/nine/pixelshader9.h @@ -0,0 +1,82 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_PIXELSHADER9_H_ +#define _NINE_PIXELSHADER9_H_ + +#include "iunknown.h" +#include "nine_shader.h" + +struct nine_lconstf; + +struct NinePixelShader9 +{ + struct NineUnknown base; + struct nine_shader_variant variant; + + struct { + const DWORD *tokens; + DWORD size; + uint8_t version; /* (major << 4) | minor */ + } byte_code; + + unsigned const_used_size; /* in bytes */ + + struct nine_lconstf lconstf; + + uint16_t sampler_mask; + uint16_t sampler_mask_shadow; + uint8_t rt_mask; + + uint64_t ff_key[6]; +}; +static INLINE struct NinePixelShader9 * +NinePixelShader9( void *data ) +{ + return (struct NinePixelShader9 *)data; +} + +void * +NinePixelShader9_GetVariant( struct NinePixelShader9 *vs, + uint32_t key ); + +/*** public ***/ + +HRESULT +NinePixelShader9_new( struct NineDevice9 *pDevice, + struct NinePixelShader9 **ppOut, + const DWORD *pFunction, void *cso ); + +HRESULT +NinePixelShader9_ctor( struct NinePixelShader9 *, + struct NineUnknownParams *pParams, + const DWORD *pFunction, void *cso ); + +void +NinePixelShader9_dtor( struct NinePixelShader9 * ); + +HRESULT WINAPI +NinePixelShader9_GetFunction( struct NinePixelShader9 *This, + void *pData, + UINT *pSizeOfData ); + +#endif /* _NINE_PIXELSHADER9_H_ */ diff --git a/src/gallium/state_trackers/nine/query9.c b/src/gallium/state_trackers/nine/query9.c new file mode 100644 index 00000000000..86762d2e697 --- /dev/null +++ b/src/gallium/state_trackers/nine/query9.c @@ -0,0 +1,358 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "query9.h" +#include "nine_helpers.h" +#include "pipe/p_context.h" +#include "util/u_math.h" +#include "nine_dump.h" + +#define DBG_CHANNEL DBG_QUERY + +#define QUERY_TYPE_MAP_CASE(a, b) case D3DQUERYTYPE_##a: return PIPE_QUERY_##b +static inline unsigned +d3dquerytype_to_pipe_query(D3DQUERYTYPE type) +{ + switch (type) { + QUERY_TYPE_MAP_CASE(EVENT, GPU_FINISHED); + QUERY_TYPE_MAP_CASE(OCCLUSION, OCCLUSION_COUNTER); + QUERY_TYPE_MAP_CASE(TIMESTAMP, TIMESTAMP); + QUERY_TYPE_MAP_CASE(TIMESTAMPDISJOINT, TIMESTAMP_DISJOINT); + QUERY_TYPE_MAP_CASE(TIMESTAMPFREQ, TIMESTAMP_DISJOINT); + QUERY_TYPE_MAP_CASE(VERTEXSTATS, PIPELINE_STATISTICS); + case D3DQUERYTYPE_VCACHE: + case D3DQUERYTYPE_RESOURCEMANAGER: + case D3DQUERYTYPE_PIPELINETIMINGS: + case D3DQUERYTYPE_INTERFACETIMINGS: + case D3DQUERYTYPE_VERTEXTIMINGS: + case D3DQUERYTYPE_PIXELTIMINGS: + case D3DQUERYTYPE_BANDWIDTHTIMINGS: + case D3DQUERYTYPE_CACHEUTILIZATION: + return PIPE_QUERY_TYPES; + default: + return ~0; + } +} + +#define GET_DATA_SIZE_CASE9(a) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_D3D9##a) +#define GET_DATA_SIZE_CASE1(a) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##a) +#define GET_DATA_SIZE_CASE2(a, b) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##b) +#define GET_DATA_SIZE_CASET(a, b) case D3DQUERYTYPE_##a: return sizeof(b) +static INLINE DWORD +nine_query_result_size(D3DQUERYTYPE type) +{ + switch (type) { + GET_DATA_SIZE_CASE1(VCACHE); + GET_DATA_SIZE_CASE1(RESOURCEMANAGER); + GET_DATA_SIZE_CASE2(VERTEXSTATS, D3DVERTEXSTATS); + GET_DATA_SIZE_CASET(EVENT, BOOL); + GET_DATA_SIZE_CASET(OCCLUSION, DWORD); + GET_DATA_SIZE_CASET(TIMESTAMP, UINT64); + GET_DATA_SIZE_CASET(TIMESTAMPDISJOINT, BOOL); + GET_DATA_SIZE_CASET(TIMESTAMPFREQ, UINT64); + GET_DATA_SIZE_CASE9(PIPELINETIMINGS); + GET_DATA_SIZE_CASE9(INTERFACETIMINGS); + GET_DATA_SIZE_CASE2(VERTEXTIMINGS, D3D9STAGETIMINGS); + GET_DATA_SIZE_CASE2(PIXELTIMINGS, D3D9STAGETIMINGS); + GET_DATA_SIZE_CASE9(BANDWIDTHTIMINGS); + GET_DATA_SIZE_CASE9(CACHEUTILIZATION); + /* GET_DATA_SIZE_CASE1(MEMORYPRESSURE); Win7 only */ + default: + assert(0); + return 0; + } +} + +HRESULT +nine_is_query_supported(D3DQUERYTYPE type) +{ + const unsigned ptype = d3dquerytype_to_pipe_query(type); + + user_assert(ptype != ~0, D3DERR_INVALIDCALL); + + if (ptype == PIPE_QUERY_TYPES) { + DBG("Query type %u (%s) not supported.\n", + type, nine_D3DQUERYTYPE_to_str(type)); + return D3DERR_NOTAVAILABLE; + } + return D3D_OK; +} + +HRESULT +NineQuery9_ctor( struct NineQuery9 *This, + struct NineUnknownParams *pParams, + D3DQUERYTYPE Type ) +{ + struct pipe_context *pipe = pParams->device->pipe; + const unsigned ptype = d3dquerytype_to_pipe_query(Type); + HRESULT hr; + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->state = NINE_QUERY_STATE_FRESH; + This->type = Type; + + user_assert(ptype != ~0, D3DERR_INVALIDCALL); + + if (ptype < PIPE_QUERY_TYPES) { + This->pq = pipe->create_query(pipe, ptype, 0); + if (!This->pq) + return E_OUTOFMEMORY; + } else { + DBG("Returning dummy NineQuery9 for %s.\n", + nine_D3DQUERYTYPE_to_str(Type)); + } + + This->instant = + Type == D3DQUERYTYPE_EVENT || + Type == D3DQUERYTYPE_RESOURCEMANAGER || + Type == D3DQUERYTYPE_TIMESTAMP || + Type == D3DQUERYTYPE_TIMESTAMPFREQ || + Type == D3DQUERYTYPE_VCACHE || + Type == D3DQUERYTYPE_VERTEXSTATS; + + This->result_size = nine_query_result_size(Type); + + return D3D_OK; +} + +void +NineQuery9_dtor( struct NineQuery9 *This ) +{ + struct pipe_context *pipe = This->base.device->pipe; + + if (This->pq) { + if (This->state == NINE_QUERY_STATE_RUNNING) + pipe->end_query(pipe, This->pq); + pipe->destroy_query(pipe, This->pq); + } + + NineUnknown_dtor(&This->base); +} + +D3DQUERYTYPE WINAPI +NineQuery9_GetType( struct NineQuery9 *This ) +{ + return This->type; +} + +DWORD WINAPI +NineQuery9_GetDataSize( struct NineQuery9 *This ) +{ + return This->result_size; +} + +HRESULT WINAPI +NineQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ) +{ + struct pipe_context *pipe = This->base.device->pipe; + + user_assert((dwIssueFlags == D3DISSUE_BEGIN && !This->instant) || + (dwIssueFlags == 0) || + (dwIssueFlags == D3DISSUE_END), D3DERR_INVALIDCALL); + + if (!This->pq) { + DBG("Issued dummy query.\n"); + return D3D_OK; + } + + if (dwIssueFlags == D3DISSUE_BEGIN) { + if (This->state == NINE_QUERY_STATE_RUNNING) { + pipe->end_query(pipe, This->pq); + } + pipe->begin_query(pipe, This->pq); + This->state = NINE_QUERY_STATE_RUNNING; + } else { + if (This->state == NINE_QUERY_STATE_RUNNING) { + pipe->end_query(pipe, This->pq); + This->state = NINE_QUERY_STATE_ENDED; + } + } + return D3D_OK; +} + +union nine_query_result +{ + D3DDEVINFO_D3DVERTEXSTATS vertexstats; + D3DDEVINFO_D3D9BANDWIDTHTIMINGS bandwidth; + D3DDEVINFO_VCACHE vcache; + D3DDEVINFO_RESOURCEMANAGER rm; + D3DDEVINFO_D3D9PIPELINETIMINGS pipe; + D3DDEVINFO_D3D9STAGETIMINGS stage; + D3DDEVINFO_D3D9INTERFACETIMINGS iface; + D3DDEVINFO_D3D9CACHEUTILIZATION cacheu; + DWORD dw; + BOOL b; + UINT64 u64; +}; + +HRESULT WINAPI +NineQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ) +{ + struct pipe_context *pipe = This->base.device->pipe; + boolean ok = !This->pq; + unsigned i; + union pipe_query_result presult; + union nine_query_result nresult; + + user_assert(This->state != NINE_QUERY_STATE_RUNNING, D3DERR_INVALIDCALL); + user_assert(dwSize == 0 || pData, D3DERR_INVALIDCALL); + user_assert(dwGetDataFlags == 0 || + dwGetDataFlags == D3DGETDATA_FLUSH, D3DERR_INVALIDCALL); + + if (!This->pq) { + DBG("No pipe query available.\n"); + if (!dwSize) + return S_OK; + } + if (This->state == NINE_QUERY_STATE_FRESH) + return S_OK; + + if (!ok) { + ok = pipe->get_query_result(pipe, This->pq, FALSE, &presult); + if (!ok) { + if (dwGetDataFlags) { + if (This->state != NINE_QUERY_STATE_FLUSHED) + pipe->flush(pipe, NULL, 0); + This->state = NINE_QUERY_STATE_FLUSHED; + } + return S_FALSE; + } + } + if (!dwSize) + return S_OK; + + switch (This->type) { + case D3DQUERYTYPE_EVENT: + nresult.b = presult.b; + break; + case D3DQUERYTYPE_OCCLUSION: + nresult.dw = presult.u64; + break; + case D3DQUERYTYPE_TIMESTAMP: + nresult.u64 = presult.u64; + break; + case D3DQUERYTYPE_TIMESTAMPDISJOINT: + nresult.b = presult.timestamp_disjoint.disjoint; + break; + case D3DQUERYTYPE_TIMESTAMPFREQ: + nresult.u64 = presult.timestamp_disjoint.frequency; + break; + case D3DQUERYTYPE_VERTEXSTATS: + nresult.vertexstats.NumRenderedTriangles = + presult.pipeline_statistics.c_invocations; + nresult.vertexstats.NumExtraClippingTriangles = + presult.pipeline_statistics.c_primitives; + break; + /* Thse might be doable with driver-specific queries; dummy for now. */ + case D3DQUERYTYPE_BANDWIDTHTIMINGS: + nresult.bandwidth.MaxBandwidthUtilized = 1.0f; + nresult.bandwidth.FrontEndUploadMemoryUtilizedPercent = 0.5f; + nresult.bandwidth.VertexRateUtilizedPercent = 0.75f; + nresult.bandwidth.TriangleSetupRateUtilizedPercent = 0.75f; + nresult.bandwidth.FillRateUtilizedPercent = 1.0f; + break; + case D3DQUERYTYPE_VERTEXTIMINGS: + case D3DQUERYTYPE_PIXELTIMINGS: + nresult.stage.MemoryProcessingPercent = 0.5f; + nresult.stage.ComputationProcessingPercent = 0.5f; + break; + case D3DQUERYTYPE_VCACHE: + /* Are we supposed to fill this in ? */ + nresult.vcache.Pattern = MAKEFOURCC('C', 'A', 'C', 'H'); + nresult.vcache.OptMethod = 1; + nresult.vcache.CacheSize = 32 << 10; + nresult.vcache.MagicNumber = 0xdeadcafe; + break; + case D3DQUERYTYPE_RESOURCEMANAGER: + /* We could record some of these in the device ... */ + for (i = 0; i < D3DRTYPECOUNT; ++i) { + nresult.rm.stats[i].bThrashing = FALSE; + nresult.rm.stats[i].ApproxBytesDownloaded = 0; + nresult.rm.stats[i].NumEvicts = 0; + nresult.rm.stats[i].NumVidCreates = 0; + nresult.rm.stats[i].LastPri = 0; + nresult.rm.stats[i].NumUsed = 1; + nresult.rm.stats[i].NumUsedInVidMem = 1; + nresult.rm.stats[i].WorkingSet = 1; + nresult.rm.stats[i].WorkingSetBytes = 1 << 20; + nresult.rm.stats[i].TotalManaged = 1; + nresult.rm.stats[i].TotalBytes = 1 << 20; + } + break; + case D3DQUERYTYPE_PIPELINETIMINGS: + nresult.pipe.VertexProcessingTimePercent = 0.4f; + nresult.pipe.PixelProcessingTimePercent = 0.4f; + nresult.pipe.OtherGPUProcessingTimePercent = 0.15f; + nresult.pipe.GPUIdleTimePercent = 0.05f; + break; + case D3DQUERYTYPE_INTERFACETIMINGS: + nresult.iface.WaitingForGPUToUseApplicationResourceTimePercent = 0.0f; + nresult.iface.WaitingForGPUToAcceptMoreCommandsTimePercent = 0.0f; + nresult.iface.WaitingForGPUToStayWithinLatencyTimePercent = 0.0f; + nresult.iface.WaitingForGPUExclusiveResourceTimePercent = 0.0f; + nresult.iface.WaitingForGPUOtherTimePercent = 0.0f; + break; + case D3DQUERYTYPE_CACHEUTILIZATION: + nresult.cacheu.TextureCacheHitRate = 0.9f; + nresult.cacheu.PostTransformVertexCacheHitRate = 0.3f; + break; + default: + assert(0); + break; + } + memcpy(pData, &nresult, MIN2(sizeof(nresult), dwSize)); + + return S_OK; +} + +IDirect3DQuery9Vtbl NineQuery9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */ + (void *)NineQuery9_GetType, + (void *)NineQuery9_GetDataSize, + (void *)NineQuery9_Issue, + (void *)NineQuery9_GetData +}; + +static const GUID *NineQuery9_IIDs[] = { + &IID_IDirect3DQuery9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineQuery9_new( struct NineDevice9 *pDevice, + struct NineQuery9 **ppOut, + D3DQUERYTYPE Type ) +{ + NINE_DEVICE_CHILD_NEW(Query9, ppOut, pDevice, Type); +} diff --git a/src/gallium/state_trackers/nine/query9.h b/src/gallium/state_trackers/nine/query9.h new file mode 100644 index 00000000000..f08393fcf34 --- /dev/null +++ b/src/gallium/state_trackers/nine/query9.h @@ -0,0 +1,83 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_QUERY9_H_ +#define _NINE_QUERY9_H_ + +#include "iunknown.h" + +enum nine_query_state +{ + NINE_QUERY_STATE_FRESH = 0, + NINE_QUERY_STATE_RUNNING, + NINE_QUERY_STATE_ENDED, + NINE_QUERY_STATE_FLUSHED +}; + +struct NineQuery9 +{ + struct NineUnknown base; + struct pipe_query *pq; + DWORD result_size; + D3DQUERYTYPE type; + enum nine_query_state state; + boolean instant; /* true if D3DISSUE_BEGIN is not needed / invalid */ +}; +static INLINE struct NineQuery9 * +NineQuery9( void *data ) +{ + return (struct NineQuery9 *)data; +} + +HRESULT +nine_is_query_supported(D3DQUERYTYPE); + +HRESULT +NineQuery9_new( struct NineDevice9 *Device, + struct NineQuery9 **ppOut, + D3DQUERYTYPE); + +HRESULT +NineQuery9_ctor( struct NineQuery9 *, + struct NineUnknownParams *pParams, + D3DQUERYTYPE Type ); + +void +NineQuery9_dtor( struct NineQuery9 * ); + +D3DQUERYTYPE WINAPI +NineQuery9_GetType( struct NineQuery9 *This ); + +DWORD WINAPI +NineQuery9_GetDataSize( struct NineQuery9 *This ); + +HRESULT WINAPI +NineQuery9_Issue( struct NineQuery9 *This, + DWORD dwIssueFlags ); + +HRESULT WINAPI +NineQuery9_GetData( struct NineQuery9 *This, + void *pData, + DWORD dwSize, + DWORD dwGetDataFlags ); + +#endif /* _NINE_QUERY9_H_ */ diff --git a/src/gallium/state_trackers/nine/resource9.c b/src/gallium/state_trackers/nine/resource9.c new file mode 100644 index 00000000000..8f535580bbf --- /dev/null +++ b/src/gallium/state_trackers/nine/resource9.c @@ -0,0 +1,230 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "resource9.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_defines.h" + +#include "pipe/p_screen.h" + +#include "util/u_hash_table.h" +#include "util/u_inlines.h" + +#include "nine_pdata.h" + +#define DBG_CHANNEL DBG_RESOURCE + + +HRESULT +NineResource9_ctor( struct NineResource9 *This, + struct NineUnknownParams *pParams, + BOOL Allocate, + D3DRESOURCETYPE Type, + D3DPOOL Pool ) +{ + struct pipe_screen *screen; + HRESULT hr; + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->info.screen = screen = This->base.device->screen; + + if (Allocate) { + DBG("(%p) Creating pipe_resource.\n", This); + This->resource = screen->resource_create(screen, &This->info); + if (!This->resource) + return D3DERR_OUTOFVIDEOMEMORY; + } + + This->data = NULL; /* FIXME remove, rather set it to null in surface9.c*/ + This->type = Type; + This->pool = Pool; + This->priority = 0; + + This->pdata = util_hash_table_create(ht_guid_hash, ht_guid_compare); + if (!This->pdata) + return E_OUTOFMEMORY; + + return D3D_OK; +} + +void +NineResource9_dtor( struct NineResource9 *This ) +{ + if (This->pdata) { + util_hash_table_foreach(This->pdata, ht_guid_delete, NULL); + util_hash_table_destroy(This->pdata); + } + + /* NOTE: We do have to use refcounting, the driver might + * still hold a reference. */ + pipe_resource_reference(&This->resource, NULL); + + /* release allocated system memory for non-D3DPOOL_DEFAULT resources */ + if (This->data) + FREE(This->data); + + NineUnknown_dtor(&This->base); +} + +struct pipe_resource * +NineResource9_GetResource( struct NineResource9 *This ) +{ + return This->resource; +} + +D3DPOOL +NineResource9_GetPool( struct NineResource9 *This ) +{ + return This->pool; +} + +HRESULT WINAPI +NineResource9_SetPrivateData( struct NineResource9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + enum pipe_error err; + struct pheader *header; + const void *user_data = pData; + + DBG("This=%p refguid=%p pData=%p SizeOfData=%u Flags=%x\n", + This, refguid, pData, SizeOfData, Flags); + + if (Flags & D3DSPD_IUNKNOWN) + user_assert(SizeOfData == sizeof(IUnknown *), D3DERR_INVALIDCALL); + + /* data consists of a header and the actual data. avoiding 2 mallocs */ + header = CALLOC_VARIANT_LENGTH_STRUCT(pheader, SizeOfData-1); + if (!header) { return E_OUTOFMEMORY; } + header->unknown = (Flags & D3DSPD_IUNKNOWN) ? TRUE : FALSE; + + /* if the refguid already exists, delete it */ + NineResource9_FreePrivateData(This, refguid); + + /* IUnknown special case */ + if (header->unknown) { + /* here the pointer doesn't point to the data we want, so point at the + * pointer making what we eventually copy is the pointer itself */ + user_data = &pData; + } + + header->size = SizeOfData; + memcpy(header->data, user_data, header->size); + + err = util_hash_table_set(This->pdata, refguid, header); + if (err == PIPE_OK) { + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); } + return D3D_OK; + } + + FREE(header); + if (err == PIPE_ERROR_OUT_OF_MEMORY) { return E_OUTOFMEMORY; } + + return D3DERR_DRIVERINTERNALERROR; +} + +HRESULT WINAPI +NineResource9_GetPrivateData( struct NineResource9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + struct pheader *header; + + DBG("This=%p refguid=%p pData=%p pSizeOfData=%p\n", + This, refguid, pData, pSizeOfData); + + user_assert(pSizeOfData, E_POINTER); + + header = util_hash_table_get(This->pdata, refguid); + if (!header) { return D3DERR_NOTFOUND; } + + if (!pData) { + *pSizeOfData = header->size; + return D3D_OK; + } + if (*pSizeOfData < header->size) { + return D3DERR_MOREDATA; + } + + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); } + memcpy(pData, header->data, header->size); + + return D3D_OK; +} + +HRESULT WINAPI +NineResource9_FreePrivateData( struct NineResource9 *This, + REFGUID refguid ) +{ + struct pheader *header; + + DBG("This=%p refguid=%p\n", This, refguid); + + header = util_hash_table_get(This->pdata, refguid); + if (!header) + return D3DERR_NOTFOUND; + + ht_guid_delete(NULL, header, NULL); + util_hash_table_remove(This->pdata, refguid); + + return D3D_OK; +} + +DWORD WINAPI +NineResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ) +{ + DWORD prev = This->priority; + This->priority = PriorityNew; + return prev; +} + +DWORD WINAPI +NineResource9_GetPriority( struct NineResource9 *This ) +{ + return This->priority; +} + +/* NOTE: Don't forget to adjust locked vtable if you change this ! */ +void WINAPI +NineResource9_PreLoad( struct NineResource9 *This ) +{ + if (This->pool != D3DPOOL_MANAGED) + return; + /* We don't treat managed vertex or index buffers different from + * default ones (are managed vertex buffers even allowed ?), and + * the PreLoad for textures is overridden by superclass. + */ +} + +D3DRESOURCETYPE WINAPI +NineResource9_GetType( struct NineResource9 *This ) +{ + return This->type; +} diff --git a/src/gallium/state_trackers/nine/resource9.h b/src/gallium/state_trackers/nine/resource9.h new file mode 100644 index 00000000000..0451498a4bf --- /dev/null +++ b/src/gallium/state_trackers/nine/resource9.h @@ -0,0 +1,107 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_RESOURCE9_H_ +#define _NINE_RESOURCE9_H_ + +#include "iunknown.h" +#include "pipe/p_state.h" + +struct pipe_screen; +struct util_hash_table; +struct NineDevice9; + +struct NineResource9 +{ + struct NineUnknown base; + + struct pipe_resource *resource; /* device resource */ + + uint8_t *data; /* system memory backing */ + + D3DRESOURCETYPE type; + D3DPOOL pool; + DWORD priority; + DWORD usage; + + struct pipe_resource info; /* resource configuration */ + + /* for [GS]etPrivateData/FreePrivateData */ + struct util_hash_table *pdata; +}; +static INLINE struct NineResource9 * +NineResource9( void *data ) +{ + return (struct NineResource9 *)data; +} + +HRESULT +NineResource9_ctor( struct NineResource9 *This, + struct NineUnknownParams *pParams, + BOOL Allocate, + D3DRESOURCETYPE Type, + D3DPOOL Pool ); + +void +NineResource9_dtor( struct NineResource9 *This ); + +/*** Nine private methods ***/ + +struct pipe_resource * +NineResource9_GetResource( struct NineResource9 *This ); + +D3DPOOL +NineResource9_GetPool( struct NineResource9 *This ); + +/*** Direct3D public methods ***/ + +HRESULT WINAPI +NineResource9_SetPrivateData( struct NineResource9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ); + +HRESULT WINAPI +NineResource9_GetPrivateData( struct NineResource9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ); + +HRESULT WINAPI +NineResource9_FreePrivateData( struct NineResource9 *This, + REFGUID refguid ); + +DWORD WINAPI +NineResource9_SetPriority( struct NineResource9 *This, + DWORD PriorityNew ); + +DWORD WINAPI +NineResource9_GetPriority( struct NineResource9 *This ); + +void WINAPI +NineResource9_PreLoad( struct NineResource9 *This ); + +D3DRESOURCETYPE WINAPI +NineResource9_GetType( struct NineResource9 *This ); + +#endif /* _NINE_RESOURCE9_H_ */ diff --git a/src/gallium/state_trackers/nine/stateblock9.c b/src/gallium/state_trackers/nine/stateblock9.c new file mode 100644 index 00000000000..ffe4ab2f196 --- /dev/null +++ b/src/gallium/state_trackers/nine/stateblock9.c @@ -0,0 +1,533 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "stateblock9.h" +#include "device9.h" +#include "basetexture9.h" +#include "nine_helpers.h" + +#define DBG_CHANNEL DBG_STATEBLOCK + +/* XXX TODO: handling of lights is broken */ + +HRESULT +NineStateBlock9_ctor( struct NineStateBlock9 *This, + struct NineUnknownParams *pParams, + enum nine_stateblock_type type ) +{ + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->type = type; + + This->state.vs_const_f = MALLOC(pParams->device->constbuf_vs->width0); + This->state.ps_const_f = MALLOC(pParams->device->constbuf_ps->width0); + if (!This->state.vs_const_f || !This->state.ps_const_f) + return E_OUTOFMEMORY; + + return D3D_OK; +} + +void +NineStateBlock9_dtor( struct NineStateBlock9 *This ) +{ + struct nine_state *state = &This->state; + struct nine_range *r; + struct nine_range_pool *pool = &This->base.device->range_pool; + + nine_state_clear(state, FALSE); + + if (state->vs_const_f) FREE(state->vs_const_f); + if (state->ps_const_f) FREE(state->ps_const_f); + + if (state->ff.light) FREE(state->ff.light); + + if (state->ff.transform) FREE(state->ff.transform); + + if (This->state.changed.ps_const_f) { + for (r = This->state.changed.ps_const_f; r->next; r = r->next); + nine_range_pool_put_chain(pool, This->state.changed.ps_const_f, r); + } + if (This->state.changed.vs_const_f) { + for (r = This->state.changed.vs_const_f; r->next; r = r->next); + nine_range_pool_put_chain(pool, This->state.changed.vs_const_f, r); + } + + NineUnknown_dtor(&This->base); +} + +/* Copy state marked changed in @mask from @src to @dst. + * If @apply is false, updating dst->changed can be omitted. + * TODO: compare ? + */ +static void +nine_state_copy_common(struct nine_state *dst, + const struct nine_state *src, + struct nine_state *mask, /* aliases either src or dst */ + const boolean apply, + struct nine_range_pool *pool) +{ + unsigned i, s; + + if (apply) + dst->changed.group |= mask->changed.group; + + if (mask->changed.group & NINE_STATE_VIEWPORT) + dst->viewport = src->viewport; + if (mask->changed.group & NINE_STATE_SCISSOR) + dst->scissor = src->scissor; + + if (mask->changed.group & NINE_STATE_VS) + nine_bind(&dst->vs, src->vs); + if (mask->changed.group & NINE_STATE_PS) + nine_bind(&dst->ps, src->ps); + + /* Vertex constants. + * + * Various possibilities for optimization here, like creating a per-SB + * constant buffer, or memcmp'ing for changes. + * Will do that later depending on what works best for specific apps. + */ + if (mask->changed.group & NINE_STATE_VS_CONST) { + struct nine_range *r; + for (r = mask->changed.vs_const_f; r; r = r->next) { + memcpy(&dst->vs_const_f[r->bgn * 4], + &src->vs_const_f[r->bgn * 4], + (r->end - r->bgn) * 4 * sizeof(float)); + if (apply) + nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end, + pool); + } + if (mask->changed.vs_const_i) { + uint16_t m = mask->changed.vs_const_i; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + memcpy(dst->vs_const_i[i], src->vs_const_i[i], 4 * sizeof(int)); + if (apply) + dst->changed.vs_const_i |= mask->changed.vs_const_i; + } + if (mask->changed.vs_const_b) { + uint16_t m = mask->changed.vs_const_b; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + dst->vs_const_b[i] = src->vs_const_b[i]; + if (apply) + dst->changed.vs_const_b |= mask->changed.vs_const_b; + } + } + + /* Pixel constants. */ + if (mask->changed.group & NINE_STATE_PS_CONST) { + struct nine_range *r; + for (r = mask->changed.ps_const_f; r; r = r->next) { + memcpy(&dst->ps_const_f[r->bgn * 4], + &src->ps_const_f[r->bgn * 4], + (r->end - r->bgn) * 4 * sizeof(float)); + if (apply) + nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end, + pool); + } + if (mask->changed.ps_const_i) { + uint16_t m = mask->changed.ps_const_i; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int)); + if (apply) + dst->changed.ps_const_i |= mask->changed.ps_const_i; + } + if (mask->changed.ps_const_b) { + uint16_t m = mask->changed.ps_const_b; + for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) + if (m & 1) + dst->ps_const_b[i] = src->ps_const_b[i]; + if (apply) + dst->changed.ps_const_b |= mask->changed.ps_const_b; + } + } + + /* Render states. + * TODO: Maybe build a list ? + */ + for (i = 0; i < Elements(dst->changed.rs); ++i) { + uint32_t m = mask->changed.rs[i]; + if (apply) + dst->changed.rs[i] |= m; + while (m) { + const int r = ffs(m) - 1; + m &= ~(1 << r); + dst->rs[i * 32 + r] = src->rs[i * 32 + r]; + } + } + + + /* Clip planes. */ + if (mask->changed.ucp) { + for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i) + if (mask->changed.ucp & (1 << i)) + memcpy(dst->clip.ucp[i], + src->clip.ucp[i], sizeof(src->clip.ucp[0])); + if (apply) + dst->changed.ucp |= mask->changed.ucp; + } + + /* Sampler state. */ + if (mask->changed.group & NINE_STATE_SAMPLER) { + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { + if (mask->changed.sampler[s] == 0x3ffe) { + memcpy(&dst->samp[s], &src->samp[s], sizeof(dst->samp[s])); + } else { + uint32_t m = mask->changed.sampler[s]; + while (m) { + const int i = ffs(m) - 1; + m &= ~(1 << i); + dst->samp[s][i] = src->samp[s][i]; + } + } + if (apply) + dst->changed.sampler[s] |= mask->changed.sampler[s]; + } + } + + /* Index buffer. */ + if (mask->changed.group & NINE_STATE_IDXBUF) + nine_bind(&dst->idxbuf, src->idxbuf); + + /* Vertex streams. */ + if (mask->changed.vtxbuf | mask->changed.stream_freq) { + uint32_t m = mask->changed.vtxbuf | mask->changed.stream_freq; + for (i = 0; m; ++i, m >>= 1) { + if (mask->changed.vtxbuf & (1 << i)) { + nine_bind(&dst->stream[i], src->stream[i]); + if (src->stream[i]) { + dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; + dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer; + dst->vtxbuf[i].stride = src->vtxbuf[i].stride; + } + } + if (mask->changed.stream_freq & (1 << i)) + dst->stream_freq[i] = src->stream_freq[i]; + } + dst->stream_instancedata_mask &= ~mask->changed.stream_freq; + dst->stream_instancedata_mask |= + src->stream_instancedata_mask & mask->changed.stream_freq; + if (apply) { + dst->changed.vtxbuf |= mask->changed.vtxbuf; + dst->changed.stream_freq |= mask->changed.stream_freq; + } + } + + if (!(mask->changed.group & NINE_STATE_FF)) + return; + WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); + + /* Fixed function state. */ + if (apply) + dst->ff.changed.group |= src->ff.changed.group; + + if (mask->changed.group & NINE_STATE_FF_MATERIAL) + dst->ff.material = src->ff.material; + + if (mask->changed.group & NINE_STATE_FF_PSSTAGES) { + for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { + for (i = 0; i < NINED3DTSS_COUNT; ++i) + if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32))) + dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i]; + if (apply) { + /* TODO: it's 32 exactly, just offset by 1 as 0 is unused */ + dst->ff.changed.tex_stage[s][0] |= + mask->ff.changed.tex_stage[s][0]; + dst->ff.changed.tex_stage[s][1] |= + mask->ff.changed.tex_stage[s][1]; + } + } + } + if (mask->changed.group & NINE_STATE_FF_LIGHTING) { + if (dst->ff.num_lights < mask->ff.num_lights) { + dst->ff.light = REALLOC(dst->ff.light, + dst->ff.num_lights * sizeof(D3DLIGHT9), + mask->ff.num_lights * sizeof(D3DLIGHT9)); + dst->ff.num_lights = mask->ff.num_lights; + } + for (i = 0; i < mask->ff.num_lights; ++i) + if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID) + dst->ff.light[i] = src->ff.light[i]; + + DBG("TODO: active lights\n"); + } + if (mask->changed.group & NINE_STATE_FF_VSTRANSF) { + for (i = 0; i < Elements(mask->ff.changed.transform); ++i) { + if (!mask->ff.changed.transform[i]) + continue; + for (s = i * 32; s < (i * 32 + 32); ++s) { + if (!(mask->ff.changed.transform[i] & (1 << (s % 32)))) + continue; + *nine_state_access_transform(dst, s, TRUE) = + *nine_state_access_transform( /* const because !alloc */ + (struct nine_state *)src, s, FALSE); + } + if (apply) + dst->ff.changed.transform[i] |= mask->ff.changed.transform[i]; + } + } +} + +static void +nine_state_copy_common_all(struct nine_state *dst, + const struct nine_state *src, + struct nine_state *help, + const boolean apply, + struct nine_range_pool *pool, + const int MaxStreams) +{ + unsigned i; + + if (apply) + dst->changed.group |= src->changed.group; + + dst->viewport = src->viewport; + dst->scissor = src->scissor; + + nine_bind(&dst->vs, src->vs); + nine_bind(&dst->ps, src->ps); + + /* Vertex constants. + * + * Various possibilities for optimization here, like creating a per-SB + * constant buffer, or memcmp'ing for changes. + * Will do that later depending on what works best for specific apps. + */ + if (1) { + struct nine_range *r = help->changed.vs_const_f; + memcpy(&dst->vs_const_f[0], + &src->vs_const_f[0], (r->end - r->bgn) * 4 * sizeof(float)); + if (apply) + nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end, pool); + + memcpy(dst->vs_const_i, src->vs_const_i, sizeof(dst->vs_const_i)); + memcpy(dst->vs_const_b, src->vs_const_b, sizeof(dst->vs_const_b)); + if (apply) { + dst->changed.vs_const_i |= src->changed.vs_const_i; + dst->changed.vs_const_b |= src->changed.vs_const_b; + } + } + + /* Pixel constants. */ + if (1) { + struct nine_range *r = help->changed.ps_const_f; + memcpy(&dst->ps_const_f[0], + &src->ps_const_f[0], (r->end - r->bgn) * 4 * sizeof(float)); + if (apply) + nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end, pool); + + memcpy(dst->ps_const_i, src->ps_const_i, sizeof(dst->ps_const_i)); + memcpy(dst->ps_const_b, src->ps_const_b, sizeof(dst->ps_const_b)); + if (apply) { + dst->changed.ps_const_i |= src->changed.ps_const_i; + dst->changed.ps_const_b |= src->changed.ps_const_b; + } + } + + /* Render states. */ + memcpy(dst->rs, src->rs, sizeof(dst->rs)); + if (apply) + memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs)); + + + /* Clip planes. */ + memcpy(&dst->clip, &src->clip, sizeof(dst->clip)); + if (apply) + dst->changed.ucp = src->changed.ucp; + + /* Sampler state. */ + memcpy(dst->samp, src->samp, sizeof(dst->samp)); + if (apply) + memcpy(dst->changed.sampler, + src->changed.sampler, sizeof(dst->changed.sampler)); + + /* Index buffer. */ + nine_bind(&dst->idxbuf, src->idxbuf); + + /* Vertex streams. */ + if (1) { + for (i = 0; i < Elements(dst->stream); ++i) { + nine_bind(&dst->stream[i], src->stream[i]); + if (src->stream[i]) { + dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; + dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer; + dst->vtxbuf[i].stride = src->vtxbuf[i].stride; + } + dst->stream_freq[i] = src->stream_freq[i]; + } + dst->stream_instancedata_mask = src->stream_instancedata_mask; + if (apply) { + dst->changed.vtxbuf = (1ULL << MaxStreams) - 1; + dst->changed.stream_freq = (1ULL << MaxStreams) - 1; + } + } + + /* keep this check in case we want to disable FF */ + if (!(help->changed.group & NINE_STATE_FF)) + return; + WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); + + /* Fixed function state. */ + if (apply) + dst->ff.changed.group = src->ff.changed.group; + + dst->ff.material = src->ff.material; + + memcpy(dst->ff.tex_stage, src->ff.tex_stage, sizeof(dst->ff.tex_stage)); + if (apply) /* TODO: memset */ + memcpy(dst->ff.changed.tex_stage, + src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage)); + + /* Lights. */ + if (1) { + if (dst->ff.num_lights < src->ff.num_lights) { + dst->ff.light = REALLOC(dst->ff.light, + dst->ff.num_lights * sizeof(D3DLIGHT9), + src->ff.num_lights * sizeof(D3DLIGHT9)); + dst->ff.num_lights = src->ff.num_lights; + } + memcpy(dst->ff.light, + src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0])); + + DBG("TODO: active lights\n"); + } + + /* Transforms. */ + if (1) { + if (dst->ff.num_transforms < src->ff.num_transforms) { + dst->ff.transform = REALLOC(dst->ff.transform, + dst->ff.num_transforms * sizeof(dst->ff.transform[0]), + src->ff.num_transforms * sizeof(src->ff.transform[0])); + dst->ff.num_transforms = src->ff.num_transforms; + } + memcpy(dst->ff.transform, + src->ff.transform, src->ff.num_transforms * sizeof(D3DMATRIX)); + if (apply) /* TODO: memset */ + memcpy(dst->ff.changed.transform, + src->ff.changed.transform, sizeof(dst->ff.changed.transform)); + } +} + +/* Capture those bits of current device state that have been changed between + * BeginStateBlock and EndStateBlock. + */ +HRESULT WINAPI +NineStateBlock9_Capture( struct NineStateBlock9 *This ) +{ + struct nine_state *dst = &This->state; + struct nine_state *src = &This->base.device->state; + const int MaxStreams = This->base.device->caps.MaxStreams; + unsigned s; + + DBG("This=%p\n", This); + + if (This->type == NINESBT_ALL) + nine_state_copy_common_all(dst, src, dst, FALSE, NULL, MaxStreams); + else + nine_state_copy_common(dst, src, dst, FALSE, NULL); + + if (dst->changed.group & NINE_STATE_VDECL) + nine_bind(&dst->vdecl, src->vdecl); + + /* Textures */ + if (dst->changed.texture) { + uint32_t m = dst->changed.texture; + for (s = 0; m; ++s, m >>= 1) + if (m & 1) + nine_bind(&dst->texture[s], src->texture[s]); + } + + return D3D_OK; +} + +/* Set state managed by this StateBlock as current device state. */ +HRESULT WINAPI +NineStateBlock9_Apply( struct NineStateBlock9 *This ) +{ + struct nine_state *dst = &This->base.device->state; + struct nine_state *src = &This->state; + struct nine_range_pool *pool = &This->base.device->range_pool; + const int MaxStreams = This->base.device->caps.MaxStreams; + unsigned s; + + DBG("This=%p\n", This); + + if (This->type == NINESBT_ALL) + nine_state_copy_common_all(dst, src, src, TRUE, pool, MaxStreams); + else + nine_state_copy_common(dst, src, src, TRUE, pool); + + if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl) + nine_bind(&dst->vdecl, src->vdecl); + + /* Textures */ + if (src->changed.texture) { + uint32_t m = src->changed.texture; + dst->changed.texture |= m; + + dst->samplers_shadow &= ~m; + + for (s = 0; m; ++s, m >>= 1) { + struct NineBaseTexture9 *tex = src->texture[s]; + if (!(m & 1)) + continue; + if (tex) { + tex->bind_count++; + if ((tex->dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list)) + list_add(&tex->list, &This->base.device->update_textures); + dst->samplers_shadow |= tex->shadow << s; + } + if (src->texture[s]) + src->texture[s]->bind_count--; + nine_bind(&dst->texture[s], src->texture[s]); + } + } + + return D3D_OK; +} + +IDirect3DStateBlock9Vtbl NineStateBlock9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */ + (void *)NineStateBlock9_Capture, + (void *)NineStateBlock9_Apply +}; + +static const GUID *NineStateBlock9_IIDs[] = { + &IID_IDirect3DStateBlock9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineStateBlock9_new( struct NineDevice9 *pDevice, + struct NineStateBlock9 **ppOut, + enum nine_stateblock_type type) +{ + NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type); +} diff --git a/src/gallium/state_trackers/nine/stateblock9.h b/src/gallium/state_trackers/nine/stateblock9.h new file mode 100644 index 00000000000..bcaf634d933 --- /dev/null +++ b/src/gallium/state_trackers/nine/stateblock9.h @@ -0,0 +1,71 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_STATEBLOCK9_H_ +#define _NINE_STATEBLOCK9_H_ + +#include "iunknown.h" + +#include "nine_state.h" + +enum nine_stateblock_type +{ + NINESBT_ALL, + NINESBT_VERTEXSTATE, + NINESBT_PIXELSTATE, + NINESBT_CUSTOM +}; + +struct NineStateBlock9 +{ + struct NineUnknown base; + + struct nine_state state; + + enum nine_stateblock_type type; +}; +static INLINE struct NineStateBlock9 * +NineStateBlock9( void *data ) +{ + return (struct NineStateBlock9 *)data; +} + +HRESULT +NineStateBlock9_new( struct NineDevice9 *, + struct NineStateBlock9 **ppOut, + enum nine_stateblock_type); + +HRESULT +NineStateBlock9_ctor( struct NineStateBlock9 *, + struct NineUnknownParams *pParams, + enum nine_stateblock_type type ); + +void +NineStateBlock9_dtor( struct NineStateBlock9 * ); + +HRESULT WINAPI +NineStateBlock9_Capture( struct NineStateBlock9 *This ); + +HRESULT WINAPI +NineStateBlock9_Apply( struct NineStateBlock9 *This ); + +#endif /* _NINE_STATEBLOCK9_H_ */ diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c new file mode 100644 index 00000000000..42a9e05dabd --- /dev/null +++ b/src/gallium/state_trackers/nine/surface9.c @@ -0,0 +1,711 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "surface9.h" +#include "device9.h" +#include "basetexture9.h" /* for marking dirty */ + +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" + +#include "util/u_math.h" +#include "util/u_inlines.h" +#include "util/u_surface.h" + +#define DBG_CHANNEL DBG_SURFACE + +HRESULT +NineSurface9_ctor( struct NineSurface9 *This, + struct NineUnknownParams *pParams, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc ) +{ + HRESULT hr; + + DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n", + This, pParams->device, pResource, Level, Layer, pDesc); + + /* Mark this as a special surface held by another internal resource. */ + pParams->container = pContainer; + + user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) || + (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL); + + assert(pResource || + pDesc->Pool != D3DPOOL_DEFAULT || pDesc->Format == D3DFMT_NULL); + + This->base.info.screen = pParams->device->screen; + This->base.info.target = PIPE_TEXTURE_2D; + This->base.info.format = d3d9_to_pipe_format(pDesc->Format); + This->base.info.width0 = pDesc->Width; + This->base.info.height0 = pDesc->Height; + This->base.info.depth0 = 1; + This->base.info.last_level = 0; + This->base.info.array_size = 1; + This->base.info.nr_samples = pDesc->MultiSampleType; + This->base.info.usage = PIPE_USAGE_DEFAULT; + This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; + This->base.info.flags = 0; + + if (pDesc->Usage & D3DUSAGE_RENDERTARGET) + This->base.info.bind |= PIPE_BIND_RENDER_TARGET; + if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL) + This->base.info.bind |= PIPE_BIND_DEPTH_STENCIL; + + if (pDesc->Pool == D3DPOOL_SYSTEMMEM) { + This->base.info.usage = PIPE_USAGE_STAGING; + if (pResource) + This->base.data = (uint8_t *)pResource; /* this is *pSharedHandle */ + pResource = NULL; + } else { + if (pResource && (pDesc->Usage & D3DUSAGE_DYNAMIC)) + pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + pipe_resource_reference(&This->base.resource, pResource); + } + + hr = NineResource9_ctor(&This->base, pParams, FALSE, D3DRTYPE_SURFACE, + pDesc->Pool); + if (FAILED(hr)) + return hr; + This->base.usage = pDesc->Usage; + + This->pipe = This->base.base.device->pipe; + This->transfer = NULL; + + This->texture = TextureType; + This->level = Level; + This->level_actual = Level; + This->layer = Layer; + This->desc = *pDesc; + + This->stride = util_format_get_stride(This->base.info.format, pDesc->Width); + This->stride = align(This->stride, 4); + + if (!pResource && !This->base.data) { + hr = NineSurface9_AllocateData(This); + if (FAILED(hr)) + return hr; + } else { + if (pResource && NineSurface9_IsOffscreenPlain(This)) + pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + } + + NineSurface9_Dump(This); + + return D3D_OK; +} + +void +NineSurface9_dtor( struct NineSurface9 *This ) +{ + if (This->transfer) + NineSurface9_UnlockRect(This); + NineSurface9_ClearDirtyRects(This); + + pipe_surface_reference(&This->surface[0], NULL); + pipe_surface_reference(&This->surface[1], NULL); + + NineResource9_dtor(&This->base); +} + +struct pipe_surface * +NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *resource = This->base.resource; + struct pipe_surface templ; + + assert(This->desc.Pool == D3DPOOL_DEFAULT || + This->desc.Pool == D3DPOOL_MANAGED); + assert(resource); + + templ.format = sRGB ? util_format_srgb(resource->format) : resource->format; + templ.u.tex.level = This->level; + templ.u.tex.first_layer = This->layer; + templ.u.tex.last_layer = This->layer; + + This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ); + assert(This->surface[sRGB]); + return This->surface[sRGB]; +} + +#ifdef DEBUG +void +NineSurface9_Dump( struct NineSurface9 *This ) +{ + struct NineBaseTexture9 *tex; + GUID id = IID_IDirect3DBaseTexture9; + REFIID ref = &id; + + DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n" + "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n" + "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->base.data, + nine_D3DPOOL_to_str(This->desc.Pool), + nine_D3DRTYPE_to_str(This->desc.Type), + nine_D3DUSAGE_to_str(This->desc.Usage), + This->desc.Width, This->desc.Height, + d3dformat_to_string(This->desc.Format), This->stride, + This->base.resource && + (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE), + This->level, This->level_actual, This->layer); + + if (!This->base.base.container) + return; + NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex); + if (tex) { + NineBaseTexture9_Dump(tex); + NineUnknown_Release(NineUnknown(tex)); + } +} +#endif /* DEBUG */ + +HRESULT WINAPI +NineSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ) +{ + HRESULT hr; + if (!NineUnknown(This)->container) + return E_NOINTERFACE; + hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer); + if (FAILED(hr)) + DBG("QueryInterface FAILED!\n"); + return hr; +} + +static INLINE void +NineSurface9_MarkContainerDirty( struct NineSurface9 *This ) +{ + if (This->texture) { + struct NineBaseTexture9 *tex = + NineBaseTexture9(This->base.base.container); + assert(tex); + assert(This->texture == D3DRTYPE_TEXTURE || + This->texture == D3DRTYPE_CUBETEXTURE); + if (This->base.pool == D3DPOOL_MANAGED) + tex->dirty = TRUE; + else + if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) + tex->dirty_mip = TRUE; + + BASETEX_REGISTER_UPDATE(tex); + } +} + +HRESULT WINAPI +NineSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ) +{ + user_assert(pDesc != NULL, E_POINTER); + *pDesc = This->desc; + return D3D_OK; +} + +/* Wine just keeps a single directy rect and expands it to cover all + * the dirty rects ever added. + * We'll keep 2, and expand the one that fits better, just for fun. + */ +INLINE void +NineSurface9_AddDirtyRect( struct NineSurface9 *This, + const struct pipe_box *box ) +{ + float area[2]; + struct u_rect rect, cover_a, cover_b; + + if (!box) { + This->dirty_rects[0].x0 = 0; + This->dirty_rects[0].y0 = 0; + This->dirty_rects[0].x1 = This->desc.Width; + This->dirty_rects[0].y1 = This->desc.Height; + + memset(&This->dirty_rects[1], 0, sizeof(This->dirty_rects[1])); + return; + } + rect.x0 = box->x; + rect.y0 = box->y; + rect.x1 = box->x + box->width; + rect.y1 = box->y + box->height; + + if (This->dirty_rects[0].x1 == 0) { + This->dirty_rects[0] = rect; + return; + } + + u_rect_union(&cover_a, &This->dirty_rects[0], &rect); + area[0] = u_rect_area(&cover_a); + + if (This->dirty_rects[1].x1 == 0) { + area[1] = u_rect_area(&This->dirty_rects[0]); + if (area[0] > (area[1] * 1.25f)) + This->dirty_rects[1] = rect; + else + This->dirty_rects[0] = cover_a; + } else { + u_rect_union(&cover_b, &This->dirty_rects[1], &rect); + area[1] = u_rect_area(&cover_b); + + if (area[0] > area[1]) + This->dirty_rects[1] = cover_b; + else + This->dirty_rects[0] = cover_a; + } +} + +static INLINE uint8_t * +NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y) +{ + unsigned x_offset = util_format_get_stride(This->base.info.format, x); + + y = util_format_get_nblocksy(This->base.info.format, y); + + assert(This->base.data); + return This->base.data + (y * This->stride + x_offset); +} + +HRESULT WINAPI +NineSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + struct pipe_resource *resource = This->base.resource; + struct pipe_box box; + unsigned usage; + + DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This, + pLockedRect, pRect, + pRect ? pRect->left : 0, pRect ? pRect->right : 0, + pRect ? pRect->top : 0, pRect ? pRect->bottom : 0, + nine_D3DLOCK_to_str(Flags)); + NineSurface9_Dump(This); + +#ifdef NINE_STRICT + user_assert(This->base.pool != D3DPOOL_DEFAULT || + (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)), + D3DERR_INVALIDCALL); +#endif + user_assert(!(Flags & ~(D3DLOCK_DISCARD | + D3DLOCK_DONOTWAIT | + D3DLOCK_NO_DIRTY_UPDATE | + D3DLOCK_NOOVERWRITE | + D3DLOCK_NOSYSLOCK | /* ignored */ + D3DLOCK_READONLY)), D3DERR_INVALIDCALL); + user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), + D3DERR_INVALIDCALL); + + /* check if it's already locked */ + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + user_assert(pLockedRect, E_POINTER); + + user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE, + D3DERR_INVALIDCALL); + + if (pRect && This->base.pool == D3DPOOL_DEFAULT && + util_format_is_compressed(This->base.info.format)) { + const unsigned w = util_format_get_blockwidth(This->base.info.format); + const unsigned h = util_format_get_blockheight(This->base.info.format); + user_assert(!(pRect->left % w) && !(pRect->right % w) && + !(pRect->top % h) && !(pRect->bottom % h), + D3DERR_INVALIDCALL); + } + + if (Flags & D3DLOCK_DISCARD) { + usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; + } else { + usage = (Flags & D3DLOCK_READONLY) ? + PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; + } + if (Flags & D3DLOCK_DONOTWAIT) + usage |= PIPE_TRANSFER_DONTBLOCK; + + if (pRect) { + rect_to_pipe_box(&box, pRect); + if (u_box_clip_2d(&box, &box, This->desc.Width, + This->desc.Height) < 0) { + DBG("pRect clipped by Width=%u Height=%u\n", + This->desc.Width, This->desc.Height); + return D3DERR_INVALIDCALL; + } + } else { + u_box_origin_2d(This->desc.Width, This->desc.Height, &box); + } + + user_warn(This->desc.Format == D3DFMT_NULL); + + if (This->base.data) { + DBG("returning system memory\n"); + + pLockedRect->Pitch = This->stride; + pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This, + box.x, box.y); + } else { + DBG("mapping pipe_resource %p (level=%u usage=%x)\n", + resource, This->level, usage); + + pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource, + This->level, usage, &box, + &This->transfer); + if (!This->transfer) { + DBG("transfer_map failed\n"); + if (Flags & D3DLOCK_DONOTWAIT) + return D3DERR_WASSTILLDRAWING; + return D3DERR_INVALIDCALL; + } + pLockedRect->Pitch = This->transfer->stride; + } + + if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { + NineSurface9_MarkContainerDirty(This); + if (This->base.pool == D3DPOOL_MANAGED) + NineSurface9_AddDirtyRect(This, &box); + } + + ++This->lock_count; + return D3D_OK; +} + +HRESULT WINAPI +NineSurface9_UnlockRect( struct NineSurface9 *This ) +{ + DBG("This=%p lock_count=%u\n", This, This->lock_count); + user_assert(This->lock_count, D3DERR_INVALIDCALL); + if (This->transfer) { + This->pipe->transfer_unmap(This->pipe, This->transfer); + This->transfer = NULL; + } + --This->lock_count; + return D3D_OK; +} + +HRESULT WINAPI +NineSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ) +{ + STUB(D3DERR_INVALIDCALL); +} + +/* nine private */ + +HRESULT +NineSurface9_AllocateData( struct NineSurface9 *This ) +{ +#if 0 + struct pipe_screen *screen = This->base.info.screen; + /* XXX: Can't use staging resource because apparently apps expect + * memory offsets to be the same across locks. + * NV50 doesn't support direct mapping yet so only enable this if + * everything else works. + */ + if (This->base.pool == D3DPOOL_SYSTEMMEM) { + /* Allocate a staging resource to save a copy: + * user -> staging resource + * staging resource -> (blit) -> video memory + * + * Instead of: + * user -> system memory + * system memory -> transfer staging area + * transfer -> video memory + * + * Does this work if we "lose" the device ? + */ + struct pipe_resource *resource; + struct pipe_resource templ; + + templ.target = PIPE_TEXTURE_2D; + templ.format = This->base.info.format; + templ.width0 = This->desc.Width; + templ.height0 = This->desc.Height; + templ.depth0 = 1; + templ.array_size = 1; + templ.last_level = 0; + templ.nr_samples = 0; + templ.usage = PIPE_USAGE_STAGING; + templ.bind = + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_TRANSFER_WRITE | + PIPE_BIND_TRANSFER_READ; + templ.flags = 0; + + DBG("(%p(This=%p),level=%u) Allocating staging resource.\n", + This->base.base.container, This, This->level); + + resource = screen->resource_create(screen, &templ); + if (!resource) + DBG("Failed to allocate staging resource.\n"); + + /* Also deallocate old staging resource. */ + pipe_resource_reference(&This->base.resource, resource); + } +#endif + if (!This->base.resource) { + const unsigned size = This->stride * + util_format_get_nblocksy(This->base.info.format, This->desc.Height); + + DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n", + This->base.base.container, This, This->level, size); + + This->base.data = (uint8_t *)MALLOC(size); + if (!This->base.data) + return E_OUTOFMEMORY; + } + return D3D_OK; +} + +IDirect3DSurface9Vtbl NineSurface9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineResource9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineSurface9_GetContainer, + (void *)NineSurface9_GetDesc, + (void *)NineSurface9_LockRect, + (void *)NineSurface9_UnlockRect, + (void *)NineSurface9_GetDC, + (void *)NineSurface9_ReleaseDC +}; + + +static INLINE boolean +NineSurface9_IsDirty(struct NineSurface9 *This) +{ + return This->dirty_rects[0].x1 != 0; +} + +HRESULT +NineSurface9_CopySurface( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *r_dst = This->base.resource; + struct pipe_resource *r_src = From->base.resource; + struct pipe_transfer *transfer; + struct pipe_box src_box; + struct pipe_box dst_box; + uint8_t *p_dst; + const uint8_t *p_src; + + user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL); + + dst_box.x = pDestPoint ? pDestPoint->x : 0; + dst_box.y = pDestPoint ? pDestPoint->y : 0; + + user_assert(dst_box.x >= 0 && + dst_box.y >= 0, D3DERR_INVALIDCALL); + + dst_box.z = This->layer; + src_box.z = From->layer; + + dst_box.depth = 1; + src_box.depth = 1; + + if (pSourceRect) { + /* make sure it doesn't range outside the source surface */ + user_assert(pSourceRect->left >= 0 && + pSourceRect->right <= From->desc.Width && + pSourceRect->top >= 0 && + pSourceRect->bottom <= From->desc.Height, + D3DERR_INVALIDCALL); + if (rect_to_pipe_box_xy_only_clamp(&src_box, pSourceRect)) + return D3D_OK; + } else { + src_box.x = 0; + src_box.y = 0; + src_box.width = From->desc.Width; + src_box.height = From->desc.Height; + } + + /* limits */ + dst_box.width = This->desc.Width - dst_box.x; + dst_box.height = This->desc.Height - dst_box.y; + + user_assert(src_box.width <= dst_box.width && + src_box.height <= dst_box.height, D3DERR_INVALIDCALL); + + dst_box.width = src_box.width; + dst_box.height = src_box.height; + + /* Don't copy to device memory of managed resources. + * We don't want to download it back again later. + */ + if (This->base.pool == D3DPOOL_MANAGED) + r_dst = NULL; + + /* Don't copy from stale device memory of managed resources. + * Also, don't copy between system and device if we don't have to. + */ + if (From->base.pool == D3DPOOL_MANAGED) { + if (!r_dst || NineSurface9_IsDirty(From)) + r_src = NULL; + } + + if (r_dst && r_src) { + pipe->resource_copy_region(pipe, + r_dst, This->level, + dst_box.x, dst_box.y, dst_box.z, + r_src, From->level, + &src_box); + } else + if (r_dst) { + p_src = NineSurface9_GetSystemMemPointer(From, src_box.x, src_box.y); + + pipe->transfer_inline_write(pipe, r_dst, This->level, + 0, /* WRITE|DISCARD are implicit */ + &dst_box, p_src, From->stride, 0); + } else + if (r_src) { + p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0); + + p_src = pipe->transfer_map(pipe, r_src, From->level, + PIPE_TRANSFER_READ, + &src_box, &transfer); + if (!p_src) + return D3DERR_DRIVERINTERNALERROR; + + util_copy_rect(p_dst, This->base.info.format, + This->stride, dst_box.x, dst_box.y, + dst_box.width, dst_box.height, + p_src, + transfer->stride, src_box.x, src_box.y); + + pipe->transfer_unmap(pipe, transfer); + } else { + p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0); + p_src = NineSurface9_GetSystemMemPointer(From, 0, 0); + + util_copy_rect(p_dst, This->base.info.format, + This->stride, dst_box.x, dst_box.y, + dst_box.width, dst_box.height, + p_src, + From->stride, src_box.x, src_box.y); + } + + if (This->base.pool == D3DPOOL_DEFAULT || + This->base.pool == D3DPOOL_MANAGED) + NineSurface9_MarkContainerDirty(This); + if (!r_dst && This->base.resource) + NineSurface9_AddDirtyRect(This, &dst_box); + + return D3D_OK; +} + +/* Gladly, rendering to a MANAGED surface is not permitted, so we will + * never have to do the reverse, i.e. download the surface. + */ +HRESULT +NineSurface9_UploadSelf( struct NineSurface9 *This ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *res = This->base.resource; + uint8_t *ptr; + unsigned i; + + assert(This->base.pool == D3DPOOL_MANAGED); + + if (!NineSurface9_IsDirty(This)) + return D3D_OK; + + for (i = 0; i < Elements(This->dirty_rects); ++i) { + struct pipe_box box; + nine_u_rect_to_pipe_box(&box, &This->dirty_rects[i], This->layer); + + if (box.width == 0) + break; + ptr = NineSurface9_GetSystemMemPointer(This, box.x, box.y); + + pipe->transfer_inline_write(pipe, res, This->level, + 0, + &box, ptr, This->stride, 0); + } + NineSurface9_ClearDirtyRects(This); + + return D3D_OK; +} + +void +NineSurface9_SetResourceResize( struct NineSurface9 *This, + struct pipe_resource *resource ) +{ + assert(This->level == 0 && This->level_actual == 0); + assert(!This->lock_count); + assert(This->desc.Pool == D3DPOOL_DEFAULT); + assert(!This->texture); + + pipe_resource_reference(&This->base.resource, resource); + + This->desc.Width = This->base.info.width0 = resource->width0; + This->desc.Height = This->base.info.height0 = resource->height0; + + This->stride = util_format_get_stride(This->base.info.format, + This->desc.Width); + This->stride = align(This->stride, 4); + + pipe_surface_reference(&This->surface[0], NULL); + pipe_surface_reference(&This->surface[1], NULL); +} + + +static const GUID *NineSurface9_IIDs[] = { + &IID_IDirect3DSurface9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineSurface9_new( struct NineDevice9 *pDevice, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc, + struct NineSurface9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */ + pContainer, pResource, + TextureType, Level, Layer, pDesc); +} diff --git a/src/gallium/state_trackers/nine/surface9.h b/src/gallium/state_trackers/nine/surface9.h new file mode 100644 index 00000000000..4a9db25237c --- /dev/null +++ b/src/gallium/state_trackers/nine/surface9.h @@ -0,0 +1,181 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_SURFACE9_H_ +#define _NINE_SURFACE9_H_ + +#include "resource9.h" + +#include "pipe/p_state.h" +#include "util/u_double_list.h" +#include "util/u_rect.h" +#include "util/u_inlines.h" + +struct NineSurface9 +{ + struct NineResource9 base; + + /* G3D state */ + struct pipe_context *pipe; + struct pipe_transfer *transfer; + struct pipe_surface *surface[2]; /* created on-demand (linear, sRGB) */ + int lock_count; + uint8_t texture; /* rtype of container BaseTex or 0 */ + + /* resource description */ + unsigned level; /* refers to the pipe_resource (SetLOD !) */ + unsigned level_actual; /* refers to the NineTexture */ + unsigned layer; + D3DSURFACE_DESC desc; + + unsigned stride; /* for system memory backing */ + + /* wine doesn't even use these, 2 will be enough */ + struct u_rect dirty_rects[2]; +}; +static INLINE struct NineSurface9 * +NineSurface9( void *data ) +{ + return (struct NineSurface9 *)data; +} + +HRESULT +NineSurface9_new( struct NineDevice9 *pDevice, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + uint8_t TextureType, /* 0 if pContainer isn't BaseTexure9 */ + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc, + struct NineSurface9 **ppOut ); + +HRESULT +NineSurface9_ctor( struct NineSurface9 *This, + struct NineUnknownParams *pParams, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + uint8_t TextureType, + unsigned Level, + unsigned Layer, + D3DSURFACE_DESC *pDesc ); + +void +NineSurface9_dtor( struct NineSurface9 *This ); + +/*** Nine private ***/ + +struct pipe_surface * +NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB ); + +static INLINE struct pipe_surface * +NineSurface9_GetSurface( struct NineSurface9 *This, int sRGB ) +{ + if (This->surface[sRGB]) + return This->surface[sRGB]; + return NineSurface9_CreatePipeSurface(This, sRGB); +} + +static INLINE struct pipe_resource * +NineSurface9_GetResource( struct NineSurface9 *This ) +{ + return This->base.resource; +} + +static INLINE void +NineSurface9_SetResource( struct NineSurface9 *This, + struct pipe_resource *resource, unsigned level ) +{ + This->level = level; + pipe_resource_reference(&This->base.resource, resource); + pipe_surface_reference(&This->surface[0], NULL); + pipe_surface_reference(&This->surface[1], NULL); +} + +void +NineSurface9_SetResourceResize( struct NineSurface9 *This, + struct pipe_resource *resource ); + +void +NineSurface9_AddDirtyRect( struct NineSurface9 *This, + const struct pipe_box *box ); + +static INLINE void +NineSurface9_ClearDirtyRects( struct NineSurface9 *This ) +{ + memset(&This->dirty_rects, 0, sizeof(This->dirty_rects)); +} + +HRESULT +NineSurface9_AllocateData( struct NineSurface9 *This ); + +HRESULT +NineSurface9_UploadSelf( struct NineSurface9 *This ); + +HRESULT +NineSurface9_CopySurface( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ); + +static INLINE boolean +NineSurface9_IsOffscreenPlain (struct NineSurface9 *This ) +{ + return This->base.usage == 0 && !This->texture; +} + +#ifdef DEBUG +void +NineSurface9_Dump( struct NineSurface9 *This ); +#else +static INLINE void +NineSurface9_Dump( struct NineSurface9 *This ) { } +#endif + +/*** Direct3D public ***/ + +HRESULT WINAPI +NineSurface9_GetContainer( struct NineSurface9 *This, + REFIID riid, + void **ppContainer ); + +HRESULT WINAPI +NineSurface9_GetDesc( struct NineSurface9 *This, + D3DSURFACE_DESC *pDesc ); + +HRESULT WINAPI +NineSurface9_LockRect( struct NineSurface9 *This, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT WINAPI +NineSurface9_UnlockRect( struct NineSurface9 *This ); + +HRESULT WINAPI +NineSurface9_GetDC( struct NineSurface9 *This, + HDC *phdc ); + +HRESULT WINAPI +NineSurface9_ReleaseDC( struct NineSurface9 *This, + HDC hdc ); + +#endif /* _NINE_SURFACE9_H_ */ diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c new file mode 100644 index 00000000000..b6e81257aba --- /dev/null +++ b/src/gallium/state_trackers/nine/swapchain9.c @@ -0,0 +1,871 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "swapchain9.h" +#include "surface9.h" +#include "device9.h" + +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "util/u_inlines.h" +#include "util/u_surface.h" +#include "hud/hud_context.h" +#include "state_tracker/drm_driver.h" + +#define DBG_CHANNEL DBG_SWAPCHAIN + +#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n) + +HRESULT +NineSwapChain9_ctor( struct NineSwapChain9 *This, + struct NineUnknownParams *pParams, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + D3DDISPLAYMODEEX *mode ) +{ + HRESULT hr; + + DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n", + This, pParams->device, pPresent, pCTX, hFocusWindow); + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->screen = NineDevice9_GetScreen(This->base.device); + This->pipe = NineDevice9_GetPipe(This->base.device); + This->cso = NineDevice9_GetCSO(This->base.device); + This->implicit = implicit; + This->actx = pCTX; + This->present = pPresent; + This->mode = NULL; + + ID3DPresent_AddRef(pPresent); + + if (!pPresentationParameters->hDeviceWindow) + pPresentationParameters->hDeviceWindow = hFocusWindow; + + This->rendering_done = FALSE; + return NineSwapChain9_Resize(This, pPresentationParameters, mode); +} + +static D3DWindowBuffer * +D3DWindowBuffer_create(struct NineSwapChain9 *This, + struct pipe_resource *resource, + int depth) +{ + D3DWindowBuffer *ret; + struct winsys_handle whandle; + int stride, dmaBufFd; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_FD; + This->screen->resource_get_handle(This->screen, resource, &whandle); + stride = whandle.stride; + dmaBufFd = whandle.handle; + ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present, + dmaBufFd, + resource->width0, + resource->height0, + stride, + depth, + 32, + &ret); + return ret; +} + +HRESULT +NineSwapChain9_Resize( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams, + D3DDISPLAYMODEEX *mode ) +{ + struct NineDevice9 *pDevice = This->base.device; + struct NineSurface9 **bufs; + D3DSURFACE_DESC desc; + HRESULT hr; + struct pipe_resource *resource, tmplt; + enum pipe_format pf; + BOOL has_present_buffers = FALSE; + int depth; + unsigned i, oldBufferCount, newBufferCount; + + DBG("This=%p pParams=%p\n", This, pParams); + user_assert(pParams != NULL, E_POINTER); + + DBG("pParams(%p):\n" + "BackBufferWidth: %u\n" + "BackBufferHeight: %u\n" + "BackBufferFormat: %s\n" + "BackBufferCount: %u\n" + "MultiSampleType: %u\n" + "MultiSampleQuality: %u\n" + "SwapEffect: %u\n" + "hDeviceWindow: %p\n" + "Windowed: %i\n" + "EnableAutoDepthStencil: %i\n" + "AutoDepthStencilFormat: %s\n" + "Flags: %s\n" + "FullScreen_RefreshRateInHz: %u\n" + "PresentationInterval: %x\n", pParams, + pParams->BackBufferWidth, pParams->BackBufferHeight, + d3dformat_to_string(pParams->BackBufferFormat), + pParams->BackBufferCount, + pParams->MultiSampleType, pParams->MultiSampleQuality, + pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed, + pParams->EnableAutoDepthStencil, + d3dformat_to_string(pParams->AutoDepthStencilFormat), + nine_D3DPRESENTFLAG_to_str(pParams->Flags), + pParams->FullScreen_RefreshRateInHz, + pParams->PresentationInterval); + + if (pParams->SwapEffect == D3DSWAPEFFECT_COPY && + pParams->BackBufferCount > 1) { + pParams->BackBufferCount = 1; + } + + if (pParams->BackBufferCount > 3) { + pParams->BackBufferCount = 3; + } + + if (pParams->BackBufferCount == 0) { + pParams->BackBufferCount = 1; + } + + if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) { + pParams->BackBufferFormat = D3DFMT_A8R8G8B8; + } + + This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0; + /* +1 because we add the fence of the current buffer before popping an old one */ + if (This->desired_fences > DRI_SWAP_FENCES_MAX) + This->desired_fences = DRI_SWAP_FENCES_MAX; + + if (mode && This->mode) { + *(This->mode) = *mode; + } else if (mode) { + This->mode = malloc(sizeof(D3DDISPLAYMODEEX)); + memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX)); + } else if (This->mode) { + free(This->mode); + This->mode = NULL; + } + + /* Note: It is the role of the backend to fill if neccessary + * BackBufferWidth and BackBufferHeight */ + ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); + + /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. + * Here we don't get back the initial content of the screen. To emulate the behaviour + * we allocate an additional buffer */ + oldBufferCount = This->params.BackBufferCount ? + (This->params.BackBufferCount + + (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0; + newBufferCount = pParams->BackBufferCount + + (pParams->SwapEffect != D3DSWAPEFFECT_COPY); + + pf = d3d9_to_pipe_format(pParams->BackBufferFormat); + if (This->actx->linear_framebuffer || + (pf != PIPE_FORMAT_B8G8R8X8_UNORM && + pf != PIPE_FORMAT_B8G8R8A8_UNORM) || + pParams->SwapEffect != D3DSWAPEFFECT_DISCARD || + pParams->MultiSampleType >= 2 || + (This->actx->ref && This->actx->ref == This->screen)) + has_present_buffers = TRUE; + + /* Note: the buffer depth has to match the window depth. + * In practice, ARGB buffers can be used with windows + * of depth 24. Windows of depth 32 are extremely rare. + * So even if the buffer is ARGB, say it is depth 24. + * It is common practice, for example that's how + * glamor implements depth 24. + * TODO: handle windows with other depths. Not possible in the short term. + * For example 16 bits.*/ + depth = 24; + + tmplt.target = PIPE_TEXTURE_2D; + tmplt.width0 = pParams->BackBufferWidth; + tmplt.height0 = pParams->BackBufferHeight; + tmplt.depth0 = 1; + tmplt.last_level = 0; + tmplt.array_size = 1; + tmplt.usage = PIPE_USAGE_DEFAULT; + tmplt.flags = 0; + + desc.Type = D3DRTYPE_SURFACE; + desc.Pool = D3DPOOL_DEFAULT; + desc.MultiSampleType = pParams->MultiSampleType; + desc.MultiSampleQuality = 0; + desc.Width = pParams->BackBufferWidth; + desc.Height = pParams->BackBufferHeight; + + for (i = 0; i < oldBufferCount; i++) { + ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); + This->present_handles[i] = NULL; + if (This->present_buffers) + pipe_resource_reference(&(This->present_buffers[i]), NULL); + } + + if (!has_present_buffers && This->present_buffers) { + FREE(This->present_buffers); + This->present_buffers = NULL; + } + + if (newBufferCount != oldBufferCount) { + for (i = newBufferCount; i < oldBufferCount; + ++i) + NineUnknown_Detach(NineUnknown(This->buffers[i])); + + bufs = REALLOC(This->buffers, + oldBufferCount * sizeof(This->buffers[0]), + newBufferCount * sizeof(This->buffers[0])); + if (!bufs) + return E_OUTOFMEMORY; + This->buffers = bufs; + if (has_present_buffers) { + This->present_buffers = REALLOC(This->present_buffers, + This->present_buffers == NULL ? 0 : oldBufferCount * sizeof(struct pipe_resource *), + newBufferCount * sizeof(struct pipe_resource *)); + memset(This->present_buffers, 0, newBufferCount * sizeof(struct pipe_resource *)); + } + This->present_handles = REALLOC(This->present_handles, + oldBufferCount * sizeof(D3DWindowBuffer *), + newBufferCount * sizeof(D3DWindowBuffer *)); + for (i = oldBufferCount; i < newBufferCount; ++i) { + This->buffers[i] = NULL; + This->present_handles[i] = NULL; + } + } + + for (i = 0; i < newBufferCount; ++i) { + tmplt.format = d3d9_to_pipe_format(pParams->BackBufferFormat); + tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET; + tmplt.nr_samples = pParams->MultiSampleType; + if (!has_present_buffers) + tmplt.bind |= PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET; + resource = This->screen->resource_create(This->screen, &tmplt); + if (!resource) { + DBG("Failed to create pipe_resource.\n"); + return D3DERR_OUTOFVIDEOMEMORY; + } + if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) + resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; + if (This->buffers[i]) { + NineSurface9_SetResourceResize(This->buffers[i], resource); + if (has_present_buffers) + pipe_resource_reference(&resource, NULL); + } else { + desc.Format = pParams->BackBufferFormat; + desc.Usage = D3DUSAGE_RENDERTARGET; + hr = NineSurface9_new(pDevice, NineUnknown(This), resource, 0, + 0, 0, &desc, &This->buffers[i]); + if (has_present_buffers) + pipe_resource_reference(&resource, NULL); + if (FAILED(hr)) { + DBG("Failed to create RT surface.\n"); + return hr; + } + This->buffers[i]->base.base.forward = FALSE; + } + if (has_present_buffers) { + tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; + tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET; + tmplt.nr_samples = 0; + if (This->actx->linear_framebuffer) + tmplt.bind |= PIPE_BIND_LINEAR; + if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD) + tmplt.bind |= PIPE_BIND_RENDER_TARGET; + resource = This->screen->resource_create(This->screen, &tmplt); + pipe_resource_reference(&(This->present_buffers[i]), resource); + } + This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth); + if (!has_present_buffers) + pipe_resource_reference(&resource, NULL); + } + if (pParams->EnableAutoDepthStencil) { + tmplt.format = d3d9_to_pipe_format(pParams->AutoDepthStencilFormat); + tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_DEPTH_STENCIL; + tmplt.nr_samples = pParams->MultiSampleType; + + resource = This->screen->resource_create(This->screen, &tmplt); + if (!resource) { + DBG("Failed to create pipe_resource for depth buffer.\n"); + return D3DERR_OUTOFVIDEOMEMORY; + } + if (This->zsbuf) { + NineSurface9_SetResourceResize(This->zsbuf, resource); + pipe_resource_reference(&resource, NULL); + } else { + /* XXX wine thinks the container of this should be the device */ + desc.Format = pParams->AutoDepthStencilFormat; + desc.Usage = D3DUSAGE_DEPTHSTENCIL; + hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, 0, + 0, 0, &desc, &This->zsbuf); + pipe_resource_reference(&resource, NULL); + if (FAILED(hr)) { + DBG("Failed to create ZS surface.\n"); + return hr; + } + This->zsbuf->base.base.forward = FALSE; + } + } + + This->params = *pParams; + + return D3D_OK; +} + +/* Throttling: code adapted from the dri state tracker */ + +/** + * swap_fences_pop_front - pull a fence from the throttle queue + * + * If the throttle queue is filled to the desired number of fences, + * pull fences off the queue until the number is less than the desired + * number of fences, and return the last fence pulled. + */ +static struct pipe_fence_handle * +swap_fences_pop_front(struct NineSwapChain9 *This) +{ + struct pipe_screen *screen = This->screen; + struct pipe_fence_handle *fence = NULL; + + if (This->desired_fences == 0) + return NULL; + + if (This->cur_fences >= This->desired_fences) { + screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); + screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); + This->tail &= DRI_SWAP_FENCES_MASK; + --This->cur_fences; + } + return fence; +} + + +/** + * swap_fences_see_front - same than swap_fences_pop_front without + * pulling + * + */ + +static struct pipe_fence_handle * +swap_fences_see_front(struct NineSwapChain9 *This) +{ + struct pipe_screen *screen = This->screen; + struct pipe_fence_handle *fence = NULL; + + if (This->desired_fences == 0) + return NULL; + + if (This->cur_fences >= This->desired_fences) { + screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); + } + return fence; +} + + +/** + * swap_fences_push_back - push a fence onto the throttle queue at the back + * + * push a fence onto the throttle queue and pull fences of the queue + * so that the desired number of fences are on the queue. + */ +static void +swap_fences_push_back(struct NineSwapChain9 *This, + struct pipe_fence_handle *fence) +{ + struct pipe_screen *screen = This->screen; + + if (!fence || This->desired_fences == 0) + return; + + while(This->cur_fences == This->desired_fences) + swap_fences_pop_front(This); + + This->cur_fences++; + screen->fence_reference(screen, &This->swap_fences[This->head++], + fence); + This->head &= DRI_SWAP_FENCES_MASK; +} + + +/** + * swap_fences_unref - empty the throttle queue + * + * pulls fences of the throttle queue until it is empty. + */ +static void +swap_fences_unref(struct NineSwapChain9 *This) +{ + struct pipe_screen *screen = This->screen; + + while(This->cur_fences) { + screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); + This->tail &= DRI_SWAP_FENCES_MASK; + --This->cur_fences; + } +} + +void +NineSwapChain9_dtor( struct NineSwapChain9 *This ) +{ + unsigned i; + + DBG("This=%p\n", This); + + if (This->buffers) { + for (i = 0; i < This->params.BackBufferCount; i++) { + NineUnknown_Destroy(NineUnknown(This->buffers[i])); + ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); + if (This->present_buffers) + pipe_resource_reference(&(This->present_buffers[i]), NULL); + } + FREE(This->buffers); + FREE(This->present_buffers); + } + if (This->zsbuf) + NineUnknown_Destroy(NineUnknown(This->zsbuf)); + + if (This->present) + ID3DPresent_Release(This->present); + + swap_fences_unref(This); + NineUnknown_dtor(&This->base); +} + +static void +create_present_buffer( struct NineSwapChain9 *This, + unsigned int width, unsigned int height, + struct pipe_resource **resource, + D3DWindowBuffer **present_handle) +{ + struct pipe_resource tmplt; + + tmplt.target = PIPE_TEXTURE_2D; + tmplt.width0 = width; + tmplt.height0 = height; + tmplt.depth0 = 1; + tmplt.last_level = 0; + tmplt.array_size = 1; + tmplt.usage = PIPE_USAGE_DEFAULT; + tmplt.flags = 0; + tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; + tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET | + PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET; + tmplt.nr_samples = 0; + if (This->actx->linear_framebuffer) + tmplt.bind |= PIPE_BIND_LINEAR; + *resource = This->screen->resource_create(This->screen, &tmplt); + + *present_handle = D3DWindowBuffer_create(This, *resource, 24); +} + +static void +handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource) +{ + struct NineDevice9 *device = This->base.device; + struct pipe_blit_info blit; + + if (device->cursor.software && device->cursor.visible && device->cursor.w) { + blit.src.resource = device->cursor.image; + blit.src.level = 0; + blit.src.format = device->cursor.image->format; + blit.src.box.x = 0; + blit.src.box.y = 0; + blit.src.box.z = 0; + blit.src.box.depth = 1; + blit.src.box.width = device->cursor.w; + blit.src.box.height = device->cursor.h; + + blit.dst.resource = resource; + blit.dst.level = 0; + blit.dst.format = resource->format; + blit.dst.box.z = 0; + blit.dst.box.depth = 1; + + blit.mask = PIPE_MASK_RGBA; + blit.filter = PIPE_TEX_FILTER_NEAREST; + blit.scissor_enable = FALSE; + + ID3DPresent_GetCursorPos(This->present, &device->cursor.pos); + + /* NOTE: blit messes up when box.x + box.width < 0, fix driver */ + blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; + blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; + blit.dst.box.width = blit.src.box.width; + blit.dst.box.height = blit.src.box.height; + + DBG("Blitting cursor(%ux%u) to (%i,%i).\n", + blit.src.box.width, blit.src.box.height, + blit.dst.box.x, blit.dst.box.y); + + This->pipe->blit(This->pipe, &blit); + } + + if (device->hud && resource) { + hud_draw(device->hud, resource); /* XXX: no offset */ + /* HUD doesn't clobber stipple */ + NineDevice9_RestoreNonCSOState(device, ~0x2); + } +} + +static INLINE HRESULT +present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + struct pipe_resource *resource; + struct pipe_fence_handle *fence; + HRESULT hr; + struct pipe_blit_info blit; + + DBG("present: This=%p pSourceRect=%p pDestRect=%p " + "pDirtyRegion=%p hDestWindowOverride=%p" + "dwFlags=%d resource=%p\n", + This, pSourceRect, pDestRect, pDirtyRegion, + hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource); + + if (pSourceRect) + DBG("pSourceRect = (%u..%u)x(%u..%u)\n", + pSourceRect->left, pSourceRect->right, + pSourceRect->top, pSourceRect->bottom); + if (pDestRect) + DBG("pDestRect = (%u..%u)x(%u..%u)\n", + pDestRect->left, pDestRect->right, + pDestRect->top, pDestRect->bottom); + + /* TODO: in the case the source and destination rect have different size: + * We need to allocate a new buffer, and do a blit to it to resize. + * We can't use the present_buffer for that since when we created it, + * we couldn't guess which size would have been needed. + * If pDestRect or pSourceRect is null, we have to check the sizes + * from the source size, and the destination window size. + * In this case, either resize rngdata, or pass NULL instead + */ + /* Note: This->buffers[0]->level should always be 0 */ + + if (This->rendering_done) + goto bypass_rendering; + + resource = This->buffers[0]->base.resource; + + if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD) + handle_draw_cursor_and_hud(This, resource); + + if (This->present_buffers) { + blit.src.resource = resource; + blit.src.level = 0; + blit.src.format = resource->format; + blit.src.box.z = 0; + blit.src.box.depth = 1; + blit.src.box.x = 0; + blit.src.box.y = 0; + blit.src.box.width = resource->width0; + blit.src.box.height = resource->height0; + + resource = This->present_buffers[0]; + + blit.dst.resource = resource; + blit.dst.level = 0; + blit.dst.format = resource->format; + blit.dst.box.z = 0; + blit.dst.box.depth = 1; + blit.dst.box.x = 0; + blit.dst.box.y = 0; + blit.dst.box.width = resource->width0; + blit.dst.box.height = resource->height0; + + blit.mask = PIPE_MASK_RGBA; + blit.filter = PIPE_TEX_FILTER_NEAREST; + blit.scissor_enable = FALSE; + + This->pipe->blit(This->pipe, &blit); + } + + if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD) + handle_draw_cursor_and_hud(This, resource); + + fence = NULL; + This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME); + if (fence) { + swap_fences_push_back(This, fence); + This->screen->fence_reference(This->screen, &fence, NULL); + } + + This->rendering_done = TRUE; +bypass_rendering: + + if (dwFlags & D3DPRESENT_DONOTWAIT) { + UNTESTED(2); + BOOL still_draw = FALSE; + fence = swap_fences_see_front(This); + if (fence) { + still_draw = !This->screen->fence_signalled(This->screen, fence); + This->screen->fence_reference(This->screen, &fence, NULL); + } + if (still_draw) + return D3DERR_WASSTILLDRAWING; + } + + fence = swap_fences_pop_front(This); + if (fence) { + (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE); + This->screen->fence_reference(This->screen, &fence, NULL); + } + + if (This->present_buffers) + resource = This->present_buffers[0]; + else + resource = This->buffers[0]->base.resource; + This->pipe->flush_resource(This->pipe, resource); + hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags); + + if (FAILED(hr)) { UNTESTED(3);return hr; } + + This->rendering_done = FALSE; + + return D3D_OK; +} + +HRESULT WINAPI +NineSwapChain9_Present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ) +{ + struct pipe_resource *res = NULL; + D3DWindowBuffer *handle_temp; + int i; + BOOL released; + HRESULT hr = present(This, pSourceRect, pDestRect, + hDestWindowOverride, pDirtyRegion, dwFlags); + + if (hr == D3DERR_WASSTILLDRAWING) + return hr; + + switch (This->params.SwapEffect) { + case D3DSWAPEFFECT_FLIP: + UNTESTED(4); + case D3DSWAPEFFECT_DISCARD: + /* rotate the queue */; + pipe_resource_reference(&res, This->buffers[0]->base.resource); + for (i = 1; i <= This->params.BackBufferCount; i++) { + NineSurface9_SetResourceResize(This->buffers[i - 1], + This->buffers[i]->base.resource); + } + NineSurface9_SetResourceResize( + This->buffers[This->params.BackBufferCount], res); + pipe_resource_reference(&res, NULL); + + if (This->present_buffers) { + pipe_resource_reference(&res, This->present_buffers[0]); + for (i = 1; i <= This->params.BackBufferCount; i++) + pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); + pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res); + pipe_resource_reference(&res, NULL); + } + + handle_temp = This->present_handles[0]; + for (i = 1; i <= This->params.BackBufferCount; i++) { + This->present_handles[i-1] = This->present_handles[i]; + } + This->present_handles[This->params.BackBufferCount] = handle_temp; + break; + + case D3DSWAPEFFECT_COPY: + UNTESTED(5); + /* do nothing */ + break; + + case D3DSWAPEFFECT_OVERLAY: + /* XXX not implemented */ + break; + + case D3DSWAPEFFECT_FLIPEX: + /* XXX not implemented */ + break; + } + + ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); + + This->base.device->state.changed.group |= NINE_STATE_FB; + nine_update_state(This->base.device, NINE_STATE_FB); + + return hr; +} + +HRESULT WINAPI +NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, + IDirect3DSurface9 *pDestSurface ) +{ + struct NineSurface9 *dest_surface = NineSurface9(pDestSurface); + struct NineDevice9 *pDevice = This->base.device; + unsigned int width, height; + struct pipe_resource *temp_resource; + struct NineSurface9 *temp_surface; + D3DWindowBuffer *temp_handle; + D3DSURFACE_DESC desc; + HRESULT hr; + + DBG("GetFrontBufferData: This=%p pDestSurface=%p\n", + This, pDestSurface); + + width = dest_surface->desc.Width; + height = dest_surface->desc.Height; + + /* Note: front window size and destination size are supposed + * to match. However it's not very clear what should get taken in Windowed + * mode. It may need a fix */ + create_present_buffer(This, width, height, &temp_resource, &temp_handle); + + desc.Type = D3DRTYPE_SURFACE; + desc.Pool = D3DPOOL_DEFAULT; + desc.MultiSampleType = D3DMULTISAMPLE_NONE; + desc.MultiSampleQuality = 0; + desc.Width = width; + desc.Height = height; + /* NineSurface9_CopySurface needs same format. */ + desc.Format = dest_surface->desc.Format; + desc.Usage = D3DUSAGE_RENDERTARGET; + hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, 0, + 0, 0, &desc, &temp_surface); + pipe_resource_reference(&temp_resource, NULL); + if (FAILED(hr)) { + DBG("Failed to create temp FrontBuffer surface.\n"); + return hr; + } + + ID3DPresent_FrontBufferCopy(This->present, temp_handle); + + NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL); + + ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); + NineUnknown_Destroy(NineUnknown(temp_surface)); + + return D3D_OK; +} + +HRESULT WINAPI +NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ) +{ + DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n", + This, iBackBuffer, Type, ppBackBuffer); + (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO); + user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL); + user_assert(ppBackBuffer != NULL, E_POINTER); + + NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer])); + *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer]; + return D3D_OK; +} + +HRESULT WINAPI +NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, + D3DRASTER_STATUS *pRasterStatus ) +{ + DBG("GetRasterStatus: This=%p pRasterStatus=%p\n", + This, pRasterStatus); + user_assert(pRasterStatus != NULL, E_POINTER); + return ID3DPresent_GetRasterStatus(This->present, pRasterStatus); +} + +HRESULT WINAPI +NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, + D3DDISPLAYMODE *pMode ) +{ + D3DDISPLAYMODEEX mode; + D3DDISPLAYROTATION rot; + HRESULT hr; + + DBG("GetDisplayMode: This=%p pMode=%p\n", + This, pMode); + user_assert(pMode != NULL, E_POINTER); + + hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot); + if (SUCCEEDED(hr)) { + pMode->Width = mode.Width; + pMode->Height = mode.Height; + pMode->RefreshRate = mode.RefreshRate; + pMode->Format = mode.Format; + } + return hr; +} + +HRESULT WINAPI +NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n", + This, pPresentationParameters); + user_assert(pPresentationParameters != NULL, E_POINTER); + *pPresentationParameters = This->params; + return D3D_OK; +} + +IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineSwapChain9_Present, + (void *)NineSwapChain9_GetFrontBufferData, + (void *)NineSwapChain9_GetBackBuffer, + (void *)NineSwapChain9_GetRasterStatus, + (void *)NineSwapChain9_GetDisplayMode, + (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */ + (void *)NineSwapChain9_GetPresentParameters +}; + +static const GUID *NineSwapChain9_IIDs[] = { + &IID_IDirect3DSwapChain9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineSwapChain9_new( struct NineDevice9 *pDevice, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + struct NineSwapChain9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */ + implicit, pPresent, pPresentationParameters, + pCTX, hFocusWindow, NULL); +} diff --git a/src/gallium/state_trackers/nine/swapchain9.h b/src/gallium/state_trackers/nine/swapchain9.h new file mode 100644 index 00000000000..566f78ab0ed --- /dev/null +++ b/src/gallium/state_trackers/nine/swapchain9.h @@ -0,0 +1,135 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_SWAPCHAIN9_H_ +#define _NINE_SWAPCHAIN9_H_ + +#include "iunknown.h" +#include "adapter9.h" + +#include "d3dadapter/d3dadapter9.h" + +struct NineDevice9; +struct NineSurface9; +struct nine_winsys_swapchain; +struct blit_state; + +#define DRI_SWAP_FENCES_MAX 4 +#define DRI_SWAP_FENCES_MASK 3 + +struct NineSwapChain9 +{ + struct NineUnknown base; + + /* G3D stuff */ + struct pipe_screen *screen; + struct pipe_context *pipe; + struct cso_context *cso; + + /* presentation backend */ + ID3DPresent *present; + D3DPRESENT_PARAMETERS params; + D3DDISPLAYMODEEX *mode; + struct d3dadapter9_context *actx; + BOOL implicit; + + /* buffer handles */ + struct NineSurface9 **buffers; /* 0 to BackBufferCount-1 : the back buffers. BackBufferCount : additional buffer */ + struct pipe_resource **present_buffers; + D3DWindowBuffer **present_handles; + + struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX]; + unsigned int cur_fences; + unsigned int head; + unsigned int tail; + unsigned int desired_fences; + + BOOL rendering_done; + + struct NineSurface9 *zsbuf; + + D3DGAMMARAMP gamma; +}; +static INLINE struct NineSwapChain9 * +NineSwapChain9( void *data ) +{ + return (struct NineSwapChain9 *)data; +} + +HRESULT +NineSwapChain9_new( struct NineDevice9 *pDevice, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + struct NineSwapChain9 **ppOut ); + +HRESULT +NineSwapChain9_ctor( struct NineSwapChain9 *This, + struct NineUnknownParams *pParams, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + D3DDISPLAYMODEEX *mode ); + +void +NineSwapChain9_dtor( struct NineSwapChain9 *This ); + +HRESULT +NineSwapChain9_Resize( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams, + D3DDISPLAYMODEEX *mode ); + +HRESULT WINAPI +NineSwapChain9_Present( struct NineSwapChain9 *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion, + DWORD dwFlags ); + +HRESULT WINAPI +NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, + IDirect3DSurface9 *pDestSurface ); + +HRESULT WINAPI +NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, + UINT iBackBuffer, + D3DBACKBUFFER_TYPE Type, + IDirect3DSurface9 **ppBackBuffer ); + +HRESULT WINAPI +NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, + D3DRASTER_STATUS *pRasterStatus ); + +HRESULT WINAPI +NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, + D3DDISPLAYMODE *pMode ); + +HRESULT WINAPI +NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + +#endif /* _NINE_SWAPCHAIN9_H_ */ diff --git a/src/gallium/state_trackers/nine/swapchain9ex.c b/src/gallium/state_trackers/nine/swapchain9ex.c new file mode 100644 index 00000000000..7207b585f08 --- /dev/null +++ b/src/gallium/state_trackers/nine/swapchain9ex.c @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "swapchain9ex.h" +#include "device9.h" + +#include "nine_helpers.h" + +#define DBG_CHANNEL DBG_SWAPCHAIN + +static HRESULT +NineSwapChain9Ex_ctor( struct NineSwapChain9Ex *This, + struct NineUnknownParams *pParams, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + D3DDISPLAYMODEEX *mode ) +{ + return NineSwapChain9_ctor(&This->base, pParams, implicit, pPresent, + pPresentationParameters, pCTX, hFocusWindow, mode); +} + +static void +NineSwapChain9Ex_dtor( struct NineSwapChain9Ex *This ) +{ + NineSwapChain9_dtor(&This->base); +} + +HRESULT WINAPI +NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ) +{ + STUB(D3DERR_INVALIDCALL); +} + +HRESULT WINAPI +NineSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ) +{ + D3DDISPLAYROTATION rot; + + user_assert(pMode != NULL, E_POINTER); + if (!pRotation) { pRotation = &rot; } + + return ID3DPresent_GetDisplayMode(This->base.present, pMode, pRotation); +} + +IDirect3DSwapChain9ExVtbl NineSwapChain9Ex_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineSwapChain9_Present, + (void *)NineSwapChain9_GetFrontBufferData, + (void *)NineSwapChain9_GetBackBuffer, + (void *)NineSwapChain9_GetRasterStatus, + (void *)NineSwapChain9_GetDisplayMode, + (void *)NineUnknown_GetDevice, /* actually part of NineSwapChain9 iface */ + (void *)NineSwapChain9_GetPresentParameters, + (void *)NineSwapChain9Ex_GetLastPresentCount, + (void *)NineSwapChain9Ex_GetPresentStats, + (void *)NineSwapChain9Ex_GetDisplayModeEx +}; + +static const GUID *NineSwapChain9Ex_IIDs[] = { + &IID_IDirect3DSwapChain9Ex, + &IID_IDirect3DSwapChain9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineSwapChain9Ex_new( struct NineDevice9 *pDevice, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + D3DDISPLAYMODEEX *mode, + struct NineSwapChain9Ex **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(SwapChain9Ex, ppOut, pDevice, /* args */ + implicit, pPresent, pPresentationParameters, + pCTX, hFocusWindow, mode); +} diff --git a/src/gallium/state_trackers/nine/swapchain9ex.h b/src/gallium/state_trackers/nine/swapchain9ex.h new file mode 100644 index 00000000000..bf407836099 --- /dev/null +++ b/src/gallium/state_trackers/nine/swapchain9ex.h @@ -0,0 +1,61 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_SWAPCHAIN9EX_H_ +#define _NINE_SWAPCHAIN9EX_H_ + +#include "swapchain9.h" + +struct NineSwapChain9Ex +{ + struct NineSwapChain9 base; +}; +static INLINE struct NineSwapChain9Ex * +NineSwapChain9Ex( void *data ) +{ + return (struct NineSwapChain9Ex *)data; +} + +HRESULT +NineSwapChain9Ex_new( struct NineDevice9 *pDevice, + BOOL implicit, + ID3DPresent *pPresent, + D3DPRESENT_PARAMETERS *pPresentationParameters, + struct d3dadapter9_context *pCTX, + HWND hFocusWindow, + D3DDISPLAYMODEEX *mode, + struct NineSwapChain9Ex **ppOut ); + +HRESULT WINAPI +NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This, + UINT *pLastPresentCount ); + +HRESULT WINAPI +NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This, + D3DPRESENTSTATS *pPresentationStatistics ); + +HRESULT WINAPI +NineSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This, + D3DDISPLAYMODEEX *pMode, + D3DDISPLAYROTATION *pRotation ); + +#endif /* _NINE_SWAPCHAIN9EX_H_ */ diff --git a/src/gallium/state_trackers/nine/texture9.c b/src/gallium/state_trackers/nine/texture9.c new file mode 100644 index 00000000000..c13268db9fd --- /dev/null +++ b/src/gallium/state_trackers/nine/texture9.c @@ -0,0 +1,342 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "surface9.h" +#include "texture9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "pipe/p_state.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "util/u_inlines.h" +#include "util/u_resource.h" + +#define DBG_CHANNEL DBG_TEXTURE + +static HRESULT +NineTexture9_ctor( struct NineTexture9 *This, + struct NineUnknownParams *pParams, + UINT Width, UINT Height, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + HANDLE *pSharedHandle ) +{ + struct pipe_screen *screen = pParams->device->screen; + struct pipe_resource *info = &This->base.base.info; + unsigned l; + D3DSURFACE_DESC sfdesc; + HRESULT hr; + const boolean shared_create = pSharedHandle && !*pSharedHandle; + + DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s " + "pSharedHandle=%p\n", This, Width, Height, Levels, + nine_D3DUSAGE_to_str(Usage), + d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle); + + user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || + (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); + + /* TODO: implement buffer sharing (should work with cross process too) + * + * Gem names may have fit but they're depreciated and won't work on render-nodes. + * One solution is to use shm buffers. We would use a /dev/shm file, fill the first + * values to tell it is a nine buffer, the size, which function created it, etc, + * and then it would contain the data. The handle would be a number, corresponding to + * the file to read (/dev/shm/nine-share-4 for example would be 4). + * + * Wine just ignores the argument, which works only if the app creates the handle + * and won't use it. Instead of failing, we support that situation by putting an + * invalid handle, that we would fail to import. Please note that we don't advertise + * the flag indicating the support for that feature, but apps seem to not care. + */ + user_assert(!pSharedHandle || + Pool == D3DPOOL_SYSTEMMEM || + Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); + + if (pSharedHandle && Pool == D3DPOOL_DEFAULT) { + /* Note: Below there is some implementation to support buffer sharing in + * this case, but it won't work for cross-process. Thus just ignore + * that code. */ + if (shared_create) { + DBG("Creating Texture with invalid handle. Importing will fail\n."); + *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */ + pSharedHandle = NULL; + } else { + ERR("Application tries to use cross-process sharing feature. Nine " + "doesn't support it"); + return D3DERR_INVALIDCALL; + } + } + + if (Usage & D3DUSAGE_AUTOGENMIPMAP) + Levels = 0; + + This->base.format = Format; + This->base.base.usage = Usage; + + info->screen = screen; + info->target = PIPE_TEXTURE_2D; + info->format = d3d9_to_pipe_format(Format); + info->width0 = Width; + info->height0 = Height; + info->depth0 = 1; + if (Levels) + info->last_level = Levels - 1; + else + info->last_level = util_logbase2(MAX2(Width, Height)); + info->array_size = 1; + info->nr_samples = 0; + info->bind = PIPE_BIND_SAMPLER_VIEW; + info->usage = PIPE_USAGE_DEFAULT; + info->flags = 0; + + if (Usage & D3DUSAGE_RENDERTARGET) + info->bind |= PIPE_BIND_RENDER_TARGET; + if (Usage & D3DUSAGE_DEPTHSTENCIL) + info->bind |= PIPE_BIND_DEPTH_STENCIL; + + if (Usage & D3DUSAGE_DYNAMIC) { + info->usage = PIPE_USAGE_DYNAMIC; + info->bind |= + PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE; + } + if (pSharedHandle) + info->bind |= PIPE_BIND_SHARED; + + if (Pool == D3DPOOL_SYSTEMMEM) + info->usage = PIPE_USAGE_STAGING; + + if (pSharedHandle && !shared_create) { + if (Pool == D3DPOOL_SYSTEMMEM) { + /* Hack for surface creation. */ + This->base.base.resource = (struct pipe_resource *)*pSharedHandle; + } else { + struct pipe_resource *res; + res = screen->resource_from_handle(screen, info, + (struct winsys_handle *)pSharedHandle); + if (!res) + return D3DERR_NOTFOUND; + This->base.base.resource = res; + } + } + + This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces)); + if (!This->surfaces) + return E_OUTOFMEMORY; + + hr = NineBaseTexture9_ctor(&This->base, pParams, D3DRTYPE_TEXTURE, Pool); + if (FAILED(hr)) + return hr; + This->base.pstype = (Height == 1) ? 1 : 0; + + /* Create all the surfaces right away. + * They manage backing storage, and transfers (LockRect) are deferred + * to them. + */ + sfdesc.Format = Format; + sfdesc.Type = D3DRTYPE_SURFACE; + sfdesc.Usage = Usage; + sfdesc.Pool = Pool; + sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; + sfdesc.MultiSampleQuality = 0; + for (l = 0; l <= info->last_level; ++l) { + sfdesc.Width = u_minify(Width, l); + sfdesc.Height = u_minify(Height, l); + + hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), + This->base.base.resource, D3DRTYPE_TEXTURE, l, 0, + &sfdesc, &This->surfaces[l]); + if (FAILED(hr)) + return hr; + } + + This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */ + + if (pSharedHandle) { + if (Pool == D3DPOOL_SYSTEMMEM) { + This->base.base.resource = NULL; + if (shared_create) + *pSharedHandle = This->surfaces[0]->base.data; + } else + if (shared_create) { + boolean ok; + ok = screen->resource_get_handle(screen, This->base.base.resource, + (struct winsys_handle *)pSharedHandle); + if (!ok) + return D3DERR_DRIVERINTERNALERROR; + } + } + + return D3D_OK; +} + +static void +NineTexture9_dtor( struct NineTexture9 *This ) +{ + unsigned l; + + if (This->surfaces) { + /* The surfaces should have 0 references and be unbound now. */ + for (l = 0; l <= This->base.base.info.last_level; ++l) + NineUnknown_Destroy(&This->surfaces[l]->base.base); + FREE(This->surfaces); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT WINAPI +NineTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + *pDesc = This->surfaces[Level]->desc; + + return D3D_OK; +} + +HRESULT WINAPI +NineTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->surfaces[Level])); + *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level]; + + return D3D_OK; +} + +HRESULT WINAPI +NineTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + return NineSurface9_LockRect(This->surfaces[Level], pLockedRect, + pRect, Flags); +} + +HRESULT WINAPI +NineTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + + return NineSurface9_UnlockRect(This->surfaces[Level]); +} + +HRESULT WINAPI +NineTexture9_AddDirtyRect( struct NineTexture9 *This, + const RECT *pDirtyRect ) +{ + DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect, + pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0, + pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0); + + /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless, + * because we always write to the final storage. Just marked it dirty in + * case we need to generate mip maps. + */ + if (This->base.base.pool != D3DPOOL_MANAGED) { + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) + This->base.dirty_mip = TRUE; + return D3D_OK; + } + This->base.dirty = TRUE; + + BASETEX_REGISTER_UPDATE(&This->base); + + if (!pDirtyRect) { + u_box_origin_2d(This->base.base.info.width0, + This->base.base.info.height0, &This->dirty_rect); + } else { + struct pipe_box box; + rect_to_pipe_box_clamp(&box, pDirtyRect); + u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box); + } + return D3D_OK; +} + +IDirect3DTexture9Vtbl NineTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineBaseTexture9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineBaseTexture9_SetLOD, + (void *)NineBaseTexture9_GetLOD, + (void *)NineBaseTexture9_GetLevelCount, + (void *)NineBaseTexture9_SetAutoGenFilterType, + (void *)NineBaseTexture9_GetAutoGenFilterType, + (void *)NineBaseTexture9_GenerateMipSubLevels, + (void *)NineTexture9_GetLevelDesc, + (void *)NineTexture9_GetSurfaceLevel, + (void *)NineTexture9_LockRect, + (void *)NineTexture9_UnlockRect, + (void *)NineTexture9_AddDirtyRect +}; + +static const GUID *NineTexture9_IIDs[] = { + &IID_IDirect3DTexture9, + &IID_IDirect3DBaseTexture9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineTexture9_new( struct NineDevice9 *pDevice, + UINT Width, UINT Height, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineTexture9 **ppOut, + HANDLE *pSharedHandle ) +{ + NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice, + Width, Height, Levels, + Usage, Format, Pool, pSharedHandle); +} diff --git a/src/gallium/state_trackers/nine/texture9.h b/src/gallium/state_trackers/nine/texture9.h new file mode 100644 index 00000000000..5e37a12cf4e --- /dev/null +++ b/src/gallium/state_trackers/nine/texture9.h @@ -0,0 +1,75 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_TEXTURE9_H_ +#define _NINE_TEXTURE9_H_ + +#include "basetexture9.h" +#include "surface9.h" + +struct NineTexture9 +{ + struct NineBaseTexture9 base; + struct NineSurface9 **surfaces; + struct pipe_box dirty_rect; /* covers all mip levels */ +}; +static INLINE struct NineTexture9 * +NineTexture9( void *data ) +{ + return (struct NineTexture9 *)data; +} + +HRESULT +NineTexture9_new( struct NineDevice9 *pDevice, + UINT Width, UINT Height, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineTexture9 **ppOut, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineTexture9_GetLevelDesc( struct NineTexture9 *This, + UINT Level, + D3DSURFACE_DESC *pDesc ); + +HRESULT WINAPI +NineTexture9_GetSurfaceLevel( struct NineTexture9 *This, + UINT Level, + IDirect3DSurface9 **ppSurfaceLevel ); + +HRESULT WINAPI +NineTexture9_LockRect( struct NineTexture9 *This, + UINT Level, + D3DLOCKED_RECT *pLockedRect, + const RECT *pRect, + DWORD Flags ); + +HRESULT WINAPI +NineTexture9_UnlockRect( struct NineTexture9 *This, + UINT Level ); + +HRESULT WINAPI +NineTexture9_AddDirtyRect( struct NineTexture9 *This, + const RECT *pDirtyRect ); + +#endif /* _NINE_TEXTURE9_H_ */ diff --git a/src/gallium/state_trackers/nine/vertexbuffer9.c b/src/gallium/state_trackers/nine/vertexbuffer9.c new file mode 100644 index 00000000000..6a57349e0dd --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexbuffer9.c @@ -0,0 +1,223 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "vertexbuffer9.h" +#include "device9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "pipe/p_format.h" +#include "util/u_box.h" + +#define DBG_CHANNEL DBG_VERTEXBUFFER + +HRESULT +NineVertexBuffer9_ctor( struct NineVertexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DVERTEXBUFFER_DESC *pDesc ) +{ + struct pipe_resource *info = &This->base.info; + HRESULT hr; + + DBG("This=%p Size=0x%x Usage=%x Pool=%u\n", This, + pDesc->Size, pDesc->Usage, pDesc->Pool); + + user_assert(pDesc->Pool != D3DPOOL_SCRATCH, D3DERR_INVALIDCALL); + + This->maps = MALLOC(sizeof(struct pipe_transfer *)); + if (!This->maps) + return E_OUTOFMEMORY; + This->nmaps = 0; + This->maxmaps = 1; + + This->pipe = pParams->device->pipe; + + info->screen = pParams->device->screen; + info->target = PIPE_BUFFER; + info->format = PIPE_FORMAT_R8_UNORM; + info->width0 = pDesc->Size; + info->flags = 0; + + info->bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_TRANSFER_WRITE; + if (!(pDesc->Usage & D3DUSAGE_WRITEONLY)) + info->bind |= PIPE_BIND_TRANSFER_READ; + + info->usage = PIPE_USAGE_DEFAULT; + if (pDesc->Usage & D3DUSAGE_DYNAMIC) + info->usage = PIPE_USAGE_STREAM; + if (pDesc->Pool == D3DPOOL_SYSTEMMEM) + info->usage = PIPE_USAGE_STAGING; + + /* if (pDesc->Usage & D3DUSAGE_DONOTCLIP) { } */ + /* if (pDesc->Usage & D3DUSAGE_NONSECURE) { } */ + /* if (pDesc->Usage & D3DUSAGE_NPATCHES) { } */ + /* if (pDesc->Usage & D3DUSAGE_POINTS) { } */ + /* if (pDesc->Usage & D3DUSAGE_RTPATCHES) { } */ + /* if (pDesc->Usage & D3DUSAGE_SOFTWAREPROCESSING) { } */ + /* if (pDesc->Usage & D3DUSAGE_TEXTAPI) { } */ + + info->height0 = 1; + info->depth0 = 1; + info->array_size = 1; + info->last_level = 0; + info->nr_samples = 0; + + hr = NineResource9_ctor(&This->base, pParams, TRUE, D3DRTYPE_VERTEXBUFFER, + pDesc->Pool); + if (FAILED(hr)) + return hr; + + pDesc->Type = D3DRTYPE_VERTEXBUFFER; + pDesc->Format = D3DFMT_VERTEXDATA; + This->desc = *pDesc; + + return D3D_OK; +} + +void +NineVertexBuffer9_dtor( struct NineVertexBuffer9 *This ) +{ + if (This->maps) { + while (This->nmaps) { + NineVertexBuffer9_Unlock(This); + } + FREE(This->maps); + } + + NineResource9_dtor(&This->base); +} + +HRESULT WINAPI +NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ) +{ + struct pipe_box box; + void *data; + const unsigned usage = d3dlock_buffer_to_pipe_transfer_usage(Flags); + + DBG("This=%p(pipe=%p) OffsetToLock=0x%x, SizeToLock=0x%x, Flags=0x%x\n", + This, This->base.resource, + OffsetToLock, SizeToLock, Flags); + + user_assert(ppbData, E_POINTER); + user_assert(!(Flags & ~(D3DLOCK_DISCARD | + D3DLOCK_DONOTWAIT | + D3DLOCK_NO_DIRTY_UPDATE | + D3DLOCK_NOSYSLOCK | + D3DLOCK_READONLY | + D3DLOCK_NOOVERWRITE)), D3DERR_INVALIDCALL); + + if (This->nmaps == This->maxmaps) { + struct pipe_transfer **newmaps = + REALLOC(This->maps, sizeof(struct pipe_transfer *)*This->maxmaps, + sizeof(struct pipe_transfer *)*(This->maxmaps << 1)); + if (newmaps == NULL) + return E_OUTOFMEMORY; + + This->maxmaps <<= 1; + This->maps = newmaps; + } + + if (SizeToLock == 0) { + SizeToLock = This->desc.Size - OffsetToLock; + user_warn(OffsetToLock != 0); + } + + u_box_1d(OffsetToLock, SizeToLock, &box); + + data = This->pipe->transfer_map(This->pipe, This->base.resource, 0, + usage, &box, &This->maps[This->nmaps]); + if (!data) { + DBG("pipe::transfer_map failed\n" + " usage = %x\n" + " box.x = %u\n" + " box.width = %u\n", + usage, box.x, box.width); + /* not sure what to return, msdn suggests this */ + if (Flags & D3DLOCK_DONOTWAIT) + return D3DERR_WASSTILLDRAWING; + return D3DERR_INVALIDCALL; + } + + This->nmaps++; + *ppbData = data; + + return D3D_OK; +} + +HRESULT WINAPI +NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ) +{ + DBG("This=%p\n", This); + + user_assert(This->nmaps > 0, D3DERR_INVALIDCALL); + This->pipe->transfer_unmap(This->pipe, This->maps[--(This->nmaps)]); + return D3D_OK; +} + +HRESULT WINAPI +NineVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This, + D3DVERTEXBUFFER_DESC *pDesc ) +{ + user_assert(pDesc, E_POINTER); + *pDesc = This->desc; + return D3D_OK; +} + +IDirect3DVertexBuffer9Vtbl NineVertexBuffer9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineResource9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineVertexBuffer9_Lock, + (void *)NineVertexBuffer9_Unlock, + (void *)NineVertexBuffer9_GetDesc +}; + +static const GUID *NineVertexBuffer9_IIDs[] = { + &IID_IDirect3DVertexBuffer9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineVertexBuffer9_new( struct NineDevice9 *pDevice, + D3DVERTEXBUFFER_DESC *pDesc, + struct NineVertexBuffer9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(VertexBuffer9, ppOut, /* args */ pDevice, pDesc); +} diff --git a/src/gallium/state_trackers/nine/vertexbuffer9.h b/src/gallium/state_trackers/nine/vertexbuffer9.h new file mode 100644 index 00000000000..0d88b839cad --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexbuffer9.h @@ -0,0 +1,76 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_VERTEXBUFFER9_H_ +#define _NINE_VERTEXBUFFER9_H_ + +#include "resource9.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_transfer; + +struct NineVertexBuffer9 +{ + struct NineResource9 base; + + /* G3D */ + struct pipe_context *pipe; + struct pipe_transfer **maps; + int nmaps, maxmaps; + + D3DVERTEXBUFFER_DESC desc; +}; +static INLINE struct NineVertexBuffer9 * +NineVertexBuffer9( void *data ) +{ + return (struct NineVertexBuffer9 *)data; +} + +HRESULT +NineVertexBuffer9_new( struct NineDevice9 *pDevice, + D3DVERTEXBUFFER_DESC *pDesc, + struct NineVertexBuffer9 **ppOut ); + +HRESULT +NineVertexBuffer9_ctor( struct NineVertexBuffer9 *This, + struct NineUnknownParams *pParams, + D3DVERTEXBUFFER_DESC *pDesc ); + +void +NineVertexBuffer9_dtor( struct NineVertexBuffer9 *This ); + +HRESULT WINAPI +NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This, + UINT OffsetToLock, + UINT SizeToLock, + void **ppbData, + DWORD Flags ); + +HRESULT WINAPI +NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This ); + +HRESULT WINAPI +NineVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This, + D3DVERTEXBUFFER_DESC *pDesc ); + +#endif /* _NINE_VERTEXBUFFER9_H_ */ diff --git a/src/gallium/state_trackers/nine/vertexdeclaration9.c b/src/gallium/state_trackers/nine/vertexdeclaration9.c new file mode 100644 index 00000000000..1a33e9348c0 --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexdeclaration9.c @@ -0,0 +1,518 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "vertexdeclaration9.h" +#include "vertexbuffer9.h" +#include "device9.h" +#include "nine_helpers.h" + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "util/u_math.h" +#include "util/u_format.h" +#include "util/u_box.h" +#include "translate/translate.h" + +#define DBG_CHANNEL DBG_VERTEXDECLARATION + +static INLINE enum pipe_format decltype_format(BYTE type) +{ + switch (type) { + case D3DDECLTYPE_FLOAT1: return PIPE_FORMAT_R32_FLOAT; + case D3DDECLTYPE_FLOAT2: return PIPE_FORMAT_R32G32_FLOAT; + case D3DDECLTYPE_FLOAT3: return PIPE_FORMAT_R32G32B32_FLOAT; + case D3DDECLTYPE_FLOAT4: return PIPE_FORMAT_R32G32B32A32_FLOAT; + case D3DDECLTYPE_D3DCOLOR: return PIPE_FORMAT_B8G8R8A8_UNORM; + case D3DDECLTYPE_UBYTE4: return PIPE_FORMAT_R8G8B8A8_USCALED; + case D3DDECLTYPE_SHORT2: return PIPE_FORMAT_R16G16_SSCALED; + case D3DDECLTYPE_SHORT4: return PIPE_FORMAT_R16G16B16A16_SSCALED; + case D3DDECLTYPE_UBYTE4N: return PIPE_FORMAT_R8G8B8A8_UNORM; + case D3DDECLTYPE_SHORT2N: return PIPE_FORMAT_R16G16_SNORM; + case D3DDECLTYPE_SHORT4N: return PIPE_FORMAT_R16G16B16A16_SNORM; + case D3DDECLTYPE_USHORT2N: return PIPE_FORMAT_R16G16_UNORM; + case D3DDECLTYPE_USHORT4N: return PIPE_FORMAT_R16G16B16A16_UNORM; + case D3DDECLTYPE_UDEC3: return PIPE_FORMAT_R10G10B10X2_USCALED; + case D3DDECLTYPE_DEC3N: return PIPE_FORMAT_R10G10B10X2_SNORM; + case D3DDECLTYPE_FLOAT16_2: return PIPE_FORMAT_R16G16_FLOAT; + case D3DDECLTYPE_FLOAT16_4: return PIPE_FORMAT_R16G16B16A16_FLOAT; + default: + assert(!"Implementation error !"); + } + return PIPE_FORMAT_NONE; +} + +static INLINE unsigned decltype_size(BYTE type) +{ + switch (type) { + case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float); + case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float); + case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float); + case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float); + case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD); + case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE); + case D3DDECLTYPE_SHORT2: return 2 * sizeof(short); + case D3DDECLTYPE_SHORT4: return 4 * sizeof(short); + case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE); + case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short); + case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short); + case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short); + case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short); + case D3DDECLTYPE_UDEC3: return 4; + case D3DDECLTYPE_DEC3N: return 4; + case D3DDECLTYPE_FLOAT16_2: return 2 * 2; + case D3DDECLTYPE_FLOAT16_4: return 4 * 2; + default: + assert(!"Implementation error !"); + } + return 0; +} + +/* Actually, arbitrary usage index values are permitted, but a + * simple lookup table won't work in that case. Let's just wait + * with making this more generic until we need it. + */ +static INLINE boolean +nine_d3ddeclusage_check(unsigned usage, unsigned usage_idx) +{ + switch (usage) { + case D3DDECLUSAGE_POSITIONT: + case D3DDECLUSAGE_PSIZE: + case D3DDECLUSAGE_TESSFACTOR: + case D3DDECLUSAGE_DEPTH: + case D3DDECLUSAGE_FOG: + case D3DDECLUSAGE_SAMPLE: + return usage_idx <= 0; + case D3DDECLUSAGE_NORMAL: + case D3DDECLUSAGE_TANGENT: + case D3DDECLUSAGE_BINORMAL: + return usage_idx <= 1; + case D3DDECLUSAGE_POSITION: + case D3DDECLUSAGE_BLENDWEIGHT: + case D3DDECLUSAGE_BLENDINDICES: + case D3DDECLUSAGE_COLOR: + return usage_idx <= 4; + case D3DDECLUSAGE_TEXCOORD: + return usage_idx <= 15; + default: + return FALSE; + } +} + +#define NINE_DECLUSAGE_CASE0(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n +#define NINE_DECLUSAGE_CASEi(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n(usage_idx) +INLINE unsigned +nine_d3d9_to_nine_declusage(unsigned usage, unsigned usage_idx) +{ + if (!nine_d3ddeclusage_check(usage, usage_idx)) + ERR("D3DDECLUSAGE_%u[%u]\n",usage,usage_idx); + assert(nine_d3ddeclusage_check(usage, usage_idx)); + switch (usage) { + NINE_DECLUSAGE_CASEi(POSITION); + NINE_DECLUSAGE_CASEi(BLENDWEIGHT); + NINE_DECLUSAGE_CASEi(BLENDINDICES); + NINE_DECLUSAGE_CASEi(NORMAL); + NINE_DECLUSAGE_CASE0(PSIZE); + NINE_DECLUSAGE_CASEi(TEXCOORD); + NINE_DECLUSAGE_CASEi(TANGENT); + NINE_DECLUSAGE_CASEi(BINORMAL); + NINE_DECLUSAGE_CASE0(TESSFACTOR); + NINE_DECLUSAGE_CASE0(POSITIONT); + NINE_DECLUSAGE_CASEi(COLOR); + NINE_DECLUSAGE_CASE0(DEPTH); + NINE_DECLUSAGE_CASE0(FOG); + NINE_DECLUSAGE_CASE0(SAMPLE); + default: + assert(!"Invalid DECLUSAGE."); + return NINE_DECLUSAGE_NONE; + } +} + +static const char *nine_declusage_names[] = +{ + [NINE_DECLUSAGE_POSITION(0)] = "POSITION", + [NINE_DECLUSAGE_POSITION(1)] = "POSITION1", + [NINE_DECLUSAGE_POSITION(2)] = "POSITION2", + [NINE_DECLUSAGE_POSITION(3)] = "POSITION3", + [NINE_DECLUSAGE_POSITION(4)] = "POSITION4", + [NINE_DECLUSAGE_BLENDWEIGHT(0)] = "BLENDWEIGHT", + [NINE_DECLUSAGE_BLENDWEIGHT(1)] = "BLENDWEIGHT1", + [NINE_DECLUSAGE_BLENDWEIGHT(2)] = "BLENDWEIGHT2", + [NINE_DECLUSAGE_BLENDWEIGHT(3)] = "BLENDWEIGHT3", + [NINE_DECLUSAGE_BLENDINDICES(0)] = "BLENDINDICES", + [NINE_DECLUSAGE_BLENDINDICES(1)] = "BLENDINDICES1", + [NINE_DECLUSAGE_BLENDINDICES(2)] = "BLENDINDICES2", + [NINE_DECLUSAGE_BLENDINDICES(3)] = "BLENDINDICES3", + [NINE_DECLUSAGE_NORMAL(0)] = "NORMAL", + [NINE_DECLUSAGE_NORMAL(1)] = "NORMAL1", + [NINE_DECLUSAGE_PSIZE] = "PSIZE", + [NINE_DECLUSAGE_TEXCOORD(0)] = "TEXCOORD0", + [NINE_DECLUSAGE_TEXCOORD(1)] = "TEXCOORD1", + [NINE_DECLUSAGE_TEXCOORD(2)] = "TEXCOORD2", + [NINE_DECLUSAGE_TEXCOORD(3)] = "TEXCOORD3", + [NINE_DECLUSAGE_TEXCOORD(4)] = "TEXCOORD4", + [NINE_DECLUSAGE_TEXCOORD(5)] = "TEXCOORD5", + [NINE_DECLUSAGE_TEXCOORD(6)] = "TEXCOORD6", + [NINE_DECLUSAGE_TEXCOORD(7)] = "TEXCOORD7", + [NINE_DECLUSAGE_TEXCOORD(8)] = "TEXCOORD8", + [NINE_DECLUSAGE_TEXCOORD(9)] = "TEXCOORD9", + [NINE_DECLUSAGE_TEXCOORD(10)] = "TEXCOORD10", + [NINE_DECLUSAGE_TEXCOORD(11)] = "TEXCOORD11", + [NINE_DECLUSAGE_TEXCOORD(12)] = "TEXCOORD12", + [NINE_DECLUSAGE_TEXCOORD(13)] = "TEXCOORD13", + [NINE_DECLUSAGE_TEXCOORD(14)] = "TEXCOORD14", + [NINE_DECLUSAGE_TEXCOORD(15)] = "TEXCOORD15", + [NINE_DECLUSAGE_TANGENT(0)] = "TANGENT", + [NINE_DECLUSAGE_TANGENT(1)] = "TANGENT1", + [NINE_DECLUSAGE_BINORMAL(0)] = "BINORMAL", + [NINE_DECLUSAGE_BINORMAL(1)] = "BINORMAL1", + [NINE_DECLUSAGE_TESSFACTOR] = "TESSFACTOR", + [NINE_DECLUSAGE_POSITIONT] = "POSITIONT", + [NINE_DECLUSAGE_COLOR(0)] = "DIFFUSE", + [NINE_DECLUSAGE_COLOR(1)] = "SPECULAR", + [NINE_DECLUSAGE_COLOR(2)] = "COLOR2", + [NINE_DECLUSAGE_COLOR(3)] = "COLOR3", + [NINE_DECLUSAGE_COLOR(4)] = "COLOR4", + [NINE_DECLUSAGE_DEPTH] = "DEPTH", + [NINE_DECLUSAGE_FOG] = "FOG", + [NINE_DECLUSAGE_NONE] = "(NONE)", + [NINE_DECLUSAGE_COUNT] = "(OOB)" +}; +static INLINE const char * +nine_declusage_name(unsigned ndcl) +{ + return nine_declusage_names[MIN2(ndcl, Elements(nine_declusage_names) - 1)]; +} + +HRESULT +NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This, + struct NineUnknownParams *pParams, + const D3DVERTEXELEMENT9 *pElements ) +{ + const D3DCAPS9 *caps; + unsigned i; + + HRESULT hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) { return hr; } + + for (This->nelems = 0; + pElements[This->nelems].Type != D3DDECLTYPE_UNUSED && + pElements[This->nelems].Stream != 0xFF; /* wine */ + ++This->nelems); + + caps = NineDevice9_GetCaps(This->base.device); + user_assert(This->nelems <= caps->MaxStreams, D3DERR_INVALIDCALL); + + This->decls = CALLOC(This->nelems+1, sizeof(D3DVERTEXELEMENT9)); + This->elems = CALLOC(This->nelems, sizeof(struct pipe_vertex_element)); + if (!This->decls || !This->elems) { return E_OUTOFMEMORY; } + memcpy(This->decls, pElements, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1)); + + memset(This->usage_map, 0xff, sizeof(This->usage_map)); + + for (i = 0; i < This->nelems; ++i) { + uint8_t usage = nine_d3d9_to_nine_declusage(This->decls[i].Usage, + This->decls[i].UsageIndex); + This->usage_map[usage] = i; + + This->elems[i].src_offset = This->decls[i].Offset; + This->elems[i].instance_divisor = 0; + This->elems[i].vertex_buffer_index = This->decls[i].Stream; + This->elems[i].src_format = decltype_format(This->decls[i].Type); + /* XXX Remember Method (tesselation), Usage, UsageIndex */ + + DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s\n", i, + This->decls[i].Stream, + This->decls[i].Offset, + util_format_name(This->elems[i].src_format), + nine_declusage_name(usage)); + } + + return D3D_OK; +} + +void +NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This ) +{ + if (This->decls) + FREE(This->decls); + if (This->elems) + FREE(This->elems); + + NineUnknown_dtor(&This->base); +} + +HRESULT WINAPI +NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, + D3DVERTEXELEMENT9 *pElement, + UINT *pNumElements ) +{ + if (!pElement) { + user_assert(pNumElements, D3DERR_INVALIDCALL); + *pNumElements = This->nelems+1; + return D3D_OK; + } + if (pNumElements) { *pNumElements = This->nelems+1; } + memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1)); + return D3D_OK; +} + +IDirect3DVertexDeclaration9Vtbl NineVertexDeclaration9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */ + (void *)NineVertexDeclaration9_GetDeclaration +}; + +static const GUID *NineVertexDeclaration9_IIDs[] = { + &IID_IDirect3DVertexDeclaration9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineVertexDeclaration9_new( struct NineDevice9 *pDevice, + const D3DVERTEXELEMENT9 *pElements, + struct NineVertexDeclaration9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements); +} + +HRESULT +NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice, + DWORD FVF, + struct NineVertexDeclaration9 **ppOut ) +{ + D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END(); + unsigned texcount, i, betas, nelems = 0; + BYTE beta_index = 0xFF; + + switch (FVF & D3DFVF_POSITION_MASK) { + case D3DFVF_XYZ: /* simple XYZ */ + case D3DFVF_XYZB1: + case D3DFVF_XYZB2: + case D3DFVF_XYZB3: + case D3DFVF_XYZB4: + case D3DFVF_XYZB5: /* XYZ with beta values */ + elems[nelems].Type = D3DDECLTYPE_FLOAT3; + elems[nelems].Usage = D3DDECLUSAGE_POSITION; + elems[nelems].UsageIndex = 0; + ++nelems; + /* simple XYZ has no beta values. break. */ + if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; } + + betas = (((FVF & D3DFVF_XYZB5)-D3DFVF_XYZB1)>>1)+1; + if (FVF & D3DFVF_LASTBETA_D3DCOLOR) { + beta_index = D3DDECLTYPE_D3DCOLOR; + } else if (FVF & D3DFVF_LASTBETA_UBYTE4) { + beta_index = D3DDECLTYPE_UBYTE4; + } else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5) { + beta_index = D3DDECLTYPE_FLOAT1; + } + if (beta_index != 0xFF) { --betas; } + + if (betas > 0) { + switch (betas) { + case 1: elems[nelems].Type = D3DDECLTYPE_FLOAT1; break; + case 2: elems[nelems].Type = D3DDECLTYPE_FLOAT2; break; + case 3: elems[nelems].Type = D3DDECLTYPE_FLOAT3; break; + case 4: elems[nelems].Type = D3DDECLTYPE_FLOAT4; break; + default: + assert(!"Implementation error!"); + } + elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT; + elems[nelems].UsageIndex = 0; + ++nelems; + } + + if (beta_index != 0xFF) { + elems[nelems].Type = beta_index; + elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES; + elems[nelems].UsageIndex = 0; + ++nelems; + } + break; + + case D3DFVF_XYZW: /* simple XYZW */ + case D3DFVF_XYZRHW: /* pretransformed XYZW */ + elems[nelems].Type = D3DDECLTYPE_FLOAT4; + elems[nelems].Usage = + ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW) ? + D3DDECLUSAGE_POSITION : D3DDECLUSAGE_POSITIONT; + elems[nelems].UsageIndex = 0; + ++nelems; + break; + + default: + (void)user_error(!"Position doesn't match any known combination"); + } + + /* normals, psize and colors */ + if (FVF & D3DFVF_NORMAL) { + elems[nelems].Type = D3DDECLTYPE_FLOAT3; + elems[nelems].Usage = D3DDECLUSAGE_NORMAL; + elems[nelems].UsageIndex = 0; + ++nelems; + } + if (FVF & D3DFVF_PSIZE) { + elems[nelems].Type = D3DDECLTYPE_FLOAT1; + elems[nelems].Usage = D3DDECLUSAGE_PSIZE; + elems[nelems].UsageIndex = 0; + ++nelems; + } + if (FVF & D3DFVF_DIFFUSE) { + elems[nelems].Type = D3DDECLTYPE_D3DCOLOR; + elems[nelems].Usage = D3DDECLUSAGE_COLOR; + elems[nelems].UsageIndex = 0; + ++nelems; + } + if (FVF & D3DFVF_SPECULAR) { + elems[nelems].Type = D3DDECLTYPE_D3DCOLOR; + elems[nelems].Usage = D3DDECLUSAGE_COLOR; + elems[nelems].UsageIndex = 1; + ++nelems; + } + + /* textures */ + texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; + if (user_error(texcount <= 8)) { texcount = 8; } + + for (i = 0; i < texcount; ++i) { + switch ((FVF >> (16+i*2)) & 0x3) { + case D3DFVF_TEXTUREFORMAT1: + elems[nelems].Type = D3DDECLTYPE_FLOAT1; + break; + + case D3DFVF_TEXTUREFORMAT2: + elems[nelems].Type = D3DDECLTYPE_FLOAT2; + break; + + case D3DFVF_TEXTUREFORMAT3: + elems[nelems].Type = D3DDECLTYPE_FLOAT3; + break; + + case D3DFVF_TEXTUREFORMAT4: + elems[nelems].Type = D3DDECLTYPE_FLOAT4; + break; + + default: + assert(!"Implementation error!"); + } + elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD; + elems[nelems].UsageIndex = i; + ++nelems; + } + + /* fill out remaining data */ + for (i = 0; i < nelems; ++i) { + elems[i].Stream = 0; + elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset + + decltype_size(elems[i-1].Type)); + elems[i].Method = D3DDECLMETHOD_DEFAULT; + } + elems[nelems++] = decl_end; + + NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems); +} + +/* ProcessVertices runs stream output into a temporary buffer to capture + * all outputs. + * Now we have to convert them to the format and order set by the vertex + * declaration, for which we use u_translate. + * This is necessary if the vertex declaration contains elements using a + * non float32 format, because stream output only supports f32/u32/s32. + */ +HRESULT +NineVertexDeclaration9_ConvertStreamOutput( + struct NineVertexDeclaration9 *This, + struct NineVertexBuffer9 *pDstBuf, + UINT DestIndex, + UINT VertexCount, + struct pipe_resource *pSrcBuf, + const struct pipe_stream_output_info *so ) +{ + struct pipe_context *pipe = This->base.device->pipe; + struct pipe_transfer *transfer = NULL; + struct translate *translate; + struct translate_key transkey; + struct pipe_box box; + HRESULT hr; + unsigned i; + void *src_map; + void *dst_map; + + transkey.output_stride = 0; + for (i = 0; i < This->nelems; ++i) { + enum pipe_format format; + + switch (so->output[i].num_components) { + case 1: format = PIPE_FORMAT_R32_FLOAT; break; + case 2: format = PIPE_FORMAT_R32G32_FLOAT; break; + case 3: format = PIPE_FORMAT_R32G32B32_FLOAT; break; + default: + assert(so->output[i].num_components == 4); + format = PIPE_FORMAT_R32G32B32A32_FLOAT; + break; + } + transkey.element[i].type = TRANSLATE_ELEMENT_NORMAL; + transkey.element[i].input_format = format; + transkey.element[i].input_buffer = 0; + transkey.element[i].input_offset = so->output[i].dst_offset * 4; + transkey.element[i].instance_divisor = 0; + + transkey.element[i].output_format = This->elems[i].src_format; + transkey.element[i].output_offset = This->elems[i].src_offset; + transkey.output_stride += + util_format_get_blocksize(This->elems[i].src_format); + + assert(!(transkey.output_stride & 3)); + } + transkey.nr_elements = This->nelems; + + translate = translate_create(&transkey); + if (!translate) + return E_OUTOFMEMORY; + + hr = NineVertexBuffer9_Lock(pDstBuf, + transkey.output_stride * DestIndex, + transkey.output_stride * VertexCount, + &dst_map, D3DLOCK_DISCARD); + if (FAILED(hr)) + goto out; + + src_map = pipe->transfer_map(pipe, pSrcBuf, 0, PIPE_TRANSFER_READ, &box, + &transfer); + if (!src_map) { + hr = D3DERR_DRIVERINTERNALERROR; + goto out; + } + translate->set_buffer(translate, 0, src_map, so->stride[0], ~0); + + translate->run(translate, 0, VertexCount, 0, 0, dst_map); + + NineVertexBuffer9_Unlock(pDstBuf); +out: + if (transfer) + pipe->transfer_unmap(pipe, transfer); + translate->release(translate); /* TODO: cache these */ + return hr; +} diff --git a/src/gallium/state_trackers/nine/vertexdeclaration9.h b/src/gallium/state_trackers/nine/vertexdeclaration9.h new file mode 100644 index 00000000000..6590f460f67 --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexdeclaration9.h @@ -0,0 +1,89 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_VERTEXDECLARATION9_H_ +#define _NINE_VERTEXDECLARATION9_H_ + +#include "nine_defines.h" +#include "iunknown.h" + +struct pipe_resource; +struct pipe_vertex_element; +struct pipe_stream_output_info; +struct NineDevice9; +struct NineVertexBuffer9; + +struct NineVertexDeclaration9 +{ + struct NineUnknown base; + + /* G3D state */ + struct pipe_vertex_element *elems; + unsigned nelems; + + /* DECLUSAGE -> element index, for selecting the vertex element + * for each VS input */ + uint8_t usage_map[NINE_DECLUSAGE_COUNT]; + + D3DVERTEXELEMENT9 *decls; + DWORD fvf; +}; +static INLINE struct NineVertexDeclaration9 * +NineVertexDeclaration9( void *data ) +{ + return (struct NineVertexDeclaration9 *)data; +} + +HRESULT +NineVertexDeclaration9_new( struct NineDevice9 *pDevice, + const D3DVERTEXELEMENT9 *pElements, + struct NineVertexDeclaration9 **ppOut ); + +HRESULT +NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice, + DWORD FVF, + struct NineVertexDeclaration9 **ppOut ); + +HRESULT +NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This, + struct NineUnknownParams *pParams, + const D3DVERTEXELEMENT9 *pElements ); + +void +NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This ); + +HRESULT WINAPI +NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, + D3DVERTEXELEMENT9 *pElement, + UINT *pNumElements ); + +/* Convert stream output data to the vertex declaration's format. */ +HRESULT +NineVertexDeclaration9_ConvertStreamOutput( + struct NineVertexDeclaration9 *This, + struct NineVertexBuffer9 *pDstBuf, + UINT DestIndex, + UINT VertexCount, + struct pipe_resource *pSrcBuf, + const struct pipe_stream_output_info *so ); + +#endif /* _NINE_VERTEXDECLARATION9_H_ */ diff --git a/src/gallium/state_trackers/nine/vertexshader9.c b/src/gallium/state_trackers/nine/vertexshader9.c new file mode 100644 index 00000000000..e04f3a5da9a --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexshader9.c @@ -0,0 +1,177 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "nine_helpers.h" +#include "nine_shader.h" + +#include "vertexshader9.h" + +#include "device9.h" +#include "pipe/p_context.h" + +#define DBG_CHANNEL DBG_VERTEXSHADER + +HRESULT +NineVertexShader9_ctor( struct NineVertexShader9 *This, + struct NineUnknownParams *pParams, + const DWORD *pFunction, void *cso ) +{ + struct NineDevice9 *device; + struct nine_shader_info info; + HRESULT hr; + unsigned i; + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + if (cso) { + This->variant.cso = cso; + return D3D_OK; + } + device = This->base.device; + + info.type = PIPE_SHADER_VERTEX; + info.byte_code = pFunction; + info.const_i_base = NINE_CONST_I_BASE(device->max_vs_const_f) / 16; + info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16; + info.sampler_mask_shadow = 0x0; + info.sampler_ps1xtypes = 0x0; + + hr = nine_translate_shader(device, &info); + if (FAILED(hr)) + return hr; + This->byte_code.version = info.version; + + This->byte_code.tokens = mem_dup(pFunction, info.byte_size); + if (!This->byte_code.tokens) + return E_OUTOFMEMORY; + This->byte_code.size = info.byte_size; + + This->variant.cso = info.cso; + This->const_used_size = info.const_used_size; + if (info.const_used_size == ~0) + This->const_used_size = NINE_CONSTBUF_SIZE(device->max_vs_const_f); + This->lconstf = info.lconstf; + This->sampler_mask = info.sampler_mask; + This->position_t = info.position_t; + This->point_size = info.point_size; + + for (i = 0; i < info.num_inputs && i < Elements(This->input_map); ++i) + This->input_map[i].ndecl = info.input_map[i]; + This->num_inputs = i; + + return D3D_OK; +} + +void +NineVertexShader9_dtor( struct NineVertexShader9 *This ) +{ + DBG("This=%p cso=%p\n", This, This->variant.cso); + + if (This->base.device) { + struct pipe_context *pipe = This->base.device->pipe; + struct nine_shader_variant *var = &This->variant; + do { + if (var->cso) { + if (This->base.device->state.cso.vs == var->cso) + pipe->bind_vs_state(pipe, NULL); + pipe->delete_vs_state(pipe, var->cso); + } + var = var->next; + } while (var); + } + nine_shader_variants_free(&This->variant); + + if (This->byte_code.tokens) + FREE((void *)This->byte_code.tokens); /* const_cast */ + + FREE(This->lconstf.data); + FREE(This->lconstf.ranges); + + NineUnknown_dtor(&This->base); +} + +HRESULT WINAPI +NineVertexShader9_GetFunction( struct NineVertexShader9 *This, + void *pData, + UINT *pSizeOfData ) +{ + user_assert(pSizeOfData, D3DERR_INVALIDCALL); + + if (!pData) { + *pSizeOfData = This->byte_code.size; + return D3D_OK; + } + user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL); + + memcpy(pData, This->byte_code.tokens, This->byte_code.size); + + return D3D_OK; +} + +void * +NineVertexShader9_GetVariant( struct NineVertexShader9 *This, + uint32_t key ) +{ + void *cso = nine_shader_variant_get(&This->variant, key); + if (!cso) { + struct NineDevice9 *device = This->base.device; + struct nine_shader_info info; + HRESULT hr; + + info.type = PIPE_SHADER_VERTEX; + info.const_i_base = NINE_CONST_I_BASE(device->max_vs_const_f) / 16; + info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16; + info.byte_code = This->byte_code.tokens; + info.sampler_mask_shadow = key & 0xf; + + hr = nine_translate_shader(This->base.device, &info); + if (FAILED(hr)) + return NULL; + nine_shader_variant_add(&This->variant, key, info.cso); + cso = info.cso; + } + return cso; +} + +IDirect3DVertexShader9Vtbl NineVertexShader9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, + (void *)NineVertexShader9_GetFunction +}; + +static const GUID *NineVertexShader9_IIDs[] = { + &IID_IDirect3DVertexShader9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineVertexShader9_new( struct NineDevice9 *pDevice, + struct NineVertexShader9 **ppOut, + const DWORD *pFunction, void *cso ) +{ + NINE_DEVICE_CHILD_NEW(VertexShader9, ppOut, pDevice, pFunction, cso); +} diff --git a/src/gallium/state_trackers/nine/vertexshader9.h b/src/gallium/state_trackers/nine/vertexshader9.h new file mode 100644 index 00000000000..a7d750d3efb --- /dev/null +++ b/src/gallium/state_trackers/nine/vertexshader9.h @@ -0,0 +1,89 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_VERTEXSHADER9_H_ +#define _NINE_VERTEXSHADER9_H_ + +#include "iunknown.h" +#include "nine_shader.h" + +struct NineVertexShader9 +{ + struct NineUnknown base; + struct nine_shader_variant variant; + + struct { + uint8_t ndecl; /* NINE_DECLUSAGE_x */ + } input_map[PIPE_MAX_ATTRIBS]; + unsigned num_inputs; + + struct { + const DWORD *tokens; + DWORD size; + uint8_t version; /* (major << 4) | minor */ + } byte_code; + + uint8_t sampler_mask; + uint8_t sampler_mask_shadow; + + boolean position_t; /* if true, disable vport transform */ + boolean point_size; /* if true, set rasterizer.point_size_per_vertex to 1 */ + + unsigned const_used_size; /* in bytes */ + + struct nine_lconstf lconstf; + + const struct pipe_stream_output_info *so; + + uint64_t ff_key[2]; +}; +static INLINE struct NineVertexShader9 * +NineVertexShader9( void *data ) +{ + return (struct NineVertexShader9 *)data; +} + +void * +NineVertexShader9_GetVariant( struct NineVertexShader9 *vs, + uint32_t key ); + +/*** public ***/ + +HRESULT +NineVertexShader9_new( struct NineDevice9 *pDevice, + struct NineVertexShader9 **ppOut, + const DWORD *pFunction, void *cso ); + +HRESULT +NineVertexShader9_ctor( struct NineVertexShader9 *, + struct NineUnknownParams *pParams, + const DWORD *pFunction, void *cso ); + +void +NineVertexShader9_dtor( struct NineVertexShader9 * ); + +HRESULT WINAPI +NineVertexShader9_GetFunction( struct NineVertexShader9 *This, + void *pData, + UINT *pSizeOfData ); + +#endif /* _NINE_VERTEXSHADER9_H_ */ diff --git a/src/gallium/state_trackers/nine/volume9.c b/src/gallium/state_trackers/nine/volume9.c new file mode 100644 index 00000000000..c46a9d1c2e0 --- /dev/null +++ b/src/gallium/state_trackers/nine/volume9.c @@ -0,0 +1,604 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "volume9.h" +#include "basetexture9.h" /* for marking dirty */ +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "util/u_hash_table.h" +#include "util/u_format.h" +#include "util/u_surface.h" +#include "nine_pdata.h" + +#define DBG_CHANNEL DBG_VOLUME + + +static HRESULT +NineVolume9_AllocateData( struct NineVolume9 *This ) +{ + unsigned size = This->layer_stride * This->desc.Depth; + + DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n", + This->base.container, This, This->level, size); + + This->data = (uint8_t *)MALLOC(size); + if (!This->data) + return E_OUTOFMEMORY; + return D3D_OK; +} + +static HRESULT +NineVolume9_ctor( struct NineVolume9 *This, + struct NineUnknownParams *pParams, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + unsigned Level, + D3DVOLUME_DESC *pDesc ) +{ + HRESULT hr; + + assert(pContainer); /* stand-alone volumes can't be created */ + + DBG("This=%p pContainer=%p pDevice=%p pResource=%p Level=%u pDesc=%p\n", + This, pContainer, pParams->device, pResource, Level, pDesc); + + /* Mark this as a special surface held by another internal resource. */ + pParams->container = pContainer; + + user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) || + (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL); + + assert(pResource || pDesc->Pool != D3DPOOL_DEFAULT); + + hr = NineUnknown_ctor(&This->base, pParams); + if (FAILED(hr)) + return hr; + + This->pdata = util_hash_table_create(ht_guid_hash, ht_guid_compare); + if (!This->pdata) + return E_OUTOFMEMORY; + + pipe_resource_reference(&This->resource, pResource); + + This->pipe = pParams->device->pipe; + This->transfer = NULL; + This->lock_count = 0; + + This->level = Level; + This->level_actual = Level; + This->desc = *pDesc; + + This->info.screen = pParams->device->screen; + This->info.target = PIPE_TEXTURE_3D; + This->info.format = d3d9_to_pipe_format(pDesc->Format); + This->info.width0 = pDesc->Width; + This->info.height0 = pDesc->Height; + This->info.depth0 = pDesc->Depth; + This->info.last_level = 0; + This->info.array_size = 1; + This->info.nr_samples = 0; + This->info.usage = PIPE_USAGE_DEFAULT; + This->info.bind = PIPE_BIND_SAMPLER_VIEW; + This->info.flags = 0; + + This->stride = util_format_get_stride(This->info.format, pDesc->Width); + This->stride = align(This->stride, 4); + This->layer_stride = util_format_get_2d_size(This->info.format, + This->stride, pDesc->Height); + + if (pDesc->Pool == D3DPOOL_SYSTEMMEM) + This->info.usage = PIPE_USAGE_STAGING; + + if (!This->resource) { + hr = NineVolume9_AllocateData(This); + if (FAILED(hr)) + return hr; + } + return D3D_OK; +} + +static void +NineVolume9_dtor( struct NineVolume9 *This ) +{ + DBG("This=%p\n", This); + + if (This->transfer) + NineVolume9_UnlockBox(This); + + pipe_resource_reference(&This->resource, NULL); + + NineUnknown_dtor(&This->base); +} + +HRESULT WINAPI +NineVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ) +{ + if (!NineUnknown(This)->container) + return E_NOINTERFACE; + return NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer); +} + +static INLINE void +NineVolume9_MarkContainerDirty( struct NineVolume9 *This ) +{ + struct NineBaseTexture9 *tex; +#ifdef DEBUG + /* This is always contained by a NineVolumeTexture9. */ + GUID id = IID_IDirect3DVolumeTexture9; + REFIID ref = &id; + assert(NineUnknown_QueryInterface(This->base.container, ref, (void **)&tex) + == S_OK); + assert(NineUnknown_Release(NineUnknown(tex)) != 0); +#endif + + tex = NineBaseTexture9(This->base.container); + assert(tex); + if (This->desc.Pool == D3DPOOL_MANAGED) + tex->dirty = TRUE; + else + if (This->desc.Usage & D3DUSAGE_AUTOGENMIPMAP) + tex->dirty_mip = TRUE; + + BASETEX_REGISTER_UPDATE(tex); +} + +HRESULT WINAPI +NineVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ) +{ + user_assert(pDesc != NULL, E_POINTER); + *pDesc = This->desc; + return D3D_OK; +} + +static INLINE boolean +NineVolume9_IsDirty(struct NineVolume9 *This) +{ + return This->dirty_box[0].width != 0; +} + +INLINE void +NineVolume9_AddDirtyRegion( struct NineVolume9 *This, + const struct pipe_box *box ) +{ + struct pipe_box cover_a, cover_b; + float vol[2]; + + if (!box) { + u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, + This->desc.Depth, &This->dirty_box[0]); + memset(&This->dirty_box[1], 0, sizeof(This->dirty_box[1])); + return; + } + if (!This->dirty_box[0].width) { + This->dirty_box[0] = *box; + return; + } + + u_box_union_3d(&cover_a, &This->dirty_box[0], box); + vol[0] = u_box_volume_3d(&cover_a); + + if (This->dirty_box[1].width == 0) { + vol[1] = u_box_volume_3d(&This->dirty_box[0]); + if (vol[0] > (vol[1] * 1.5f)) + This->dirty_box[1] = *box; + else + This->dirty_box[0] = cover_a; + } else { + u_box_union_3d(&cover_b, &This->dirty_box[1], box); + vol[1] = u_box_volume_3d(&cover_b); + + if (vol[0] > vol[1]) + This->dirty_box[1] = cover_b; + else + This->dirty_box[0] = cover_a; + } +} + +static INLINE uint8_t * +NineVolume9_GetSystemMemPointer(struct NineVolume9 *This, int x, int y, int z) +{ + unsigned x_offset = util_format_get_stride(This->info.format, x); + + y = util_format_get_nblocksy(This->info.format, y); + + assert(This->data); + return This->data + (z * This->layer_stride + y * This->stride + x_offset); +} + +HRESULT WINAPI +NineVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + struct pipe_resource *resource = This->resource; + struct pipe_box box; + unsigned usage; + + DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n", + This, This->base.container, pLockedVolume, pBox, + pBox ? pBox->Left : 0, pBox ? pBox->Right : 0, + pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0, + pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, + nine_D3DLOCK_to_str(Flags)); + + user_assert(This->desc.Pool != D3DPOOL_DEFAULT || + (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); + + user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), + D3DERR_INVALIDCALL); + + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + user_assert(pLockedVolume, E_POINTER); + + if (pBox && This->desc.Pool == D3DPOOL_DEFAULT && + util_format_is_compressed(This->info.format)) { + const unsigned w = util_format_get_blockwidth(This->info.format); + const unsigned h = util_format_get_blockheight(This->info.format); + user_assert(!(pBox->Left % w) && !(pBox->Right % w) && + !(pBox->Top % h) && !(pBox->Bottom % h), + D3DERR_INVALIDCALL); + } + + if (Flags & D3DLOCK_DISCARD) { + usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE; + } else { + usage = (Flags & D3DLOCK_READONLY) ? + PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE; + } + if (Flags & D3DLOCK_DONOTWAIT) + usage |= PIPE_TRANSFER_DONTBLOCK; + + if (pBox) { + d3dbox_to_pipe_box(&box, pBox); + if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) { + DBG("Locked volume intersection empty.\n"); + return D3DERR_INVALIDCALL; + } + } else { + u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, + &box); + } + + if (This->data) { + pLockedVolume->RowPitch = This->stride; + pLockedVolume->SlicePitch = This->layer_stride; + pLockedVolume->pBits = + NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); + } else { + pLockedVolume->pBits = + This->pipe->transfer_map(This->pipe, resource, This->level, usage, + &box, &This->transfer); + if (!This->transfer) { + if (Flags & D3DLOCK_DONOTWAIT) + return D3DERR_WASSTILLDRAWING; + return D3DERR_DRIVERINTERNALERROR; + } + pLockedVolume->RowPitch = This->transfer->stride; + pLockedVolume->SlicePitch = This->transfer->layer_stride; + } + + if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { + NineVolume9_MarkContainerDirty(This); + if (This->desc.Pool == D3DPOOL_MANAGED) + NineVolume9_AddDirtyRegion(This, &box); + } + + ++This->lock_count; + return D3D_OK; +} + +HRESULT WINAPI +NineVolume9_UnlockBox( struct NineVolume9 *This ) +{ + DBG("This=%p lock_count=%u\n", This, This->lock_count); + user_assert(This->lock_count, D3DERR_INVALIDCALL); + if (This->transfer) { + This->pipe->transfer_unmap(This->pipe, This->transfer); + This->transfer = NULL; + } + --This->lock_count; + return D3D_OK; +} + + +HRESULT +NineVolume9_CopyVolume( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *r_dst = This->resource; + struct pipe_resource *r_src = From->resource; + struct pipe_transfer *transfer; + struct pipe_box src_box; + struct pipe_box dst_box; + uint8_t *p_dst; + const uint8_t *p_src; + + user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL); + + dst_box.x = dstx; + dst_box.y = dsty; + dst_box.z = dstz; + + if (pSrcBox) { + /* make sure it doesn't range outside the source volume */ + user_assert(pSrcBox->x >= 0 && + (pSrcBox->width - pSrcBox->x) <= From->desc.Width && + pSrcBox->y >= 0 && + (pSrcBox->height - pSrcBox->y) <= From->desc.Height && + pSrcBox->z >= 0 && + (pSrcBox->depth - pSrcBox->z) <= From->desc.Depth, + D3DERR_INVALIDCALL); + src_box = *pSrcBox; + } else { + src_box.x = 0; + src_box.y = 0; + src_box.z = 0; + src_box.width = From->desc.Width; + src_box.height = From->desc.Height; + src_box.depth = From->desc.Depth; + } + /* limits */ + dst_box.width = This->desc.Width - dst_box.x; + dst_box.height = This->desc.Height - dst_box.y; + dst_box.depth = This->desc.Depth - dst_box.z; + + user_assert(src_box.width <= dst_box.width && + src_box.height <= dst_box.height && + src_box.depth <= dst_box.depth, D3DERR_INVALIDCALL); + + dst_box.width = src_box.width; + dst_box.height = src_box.height; + dst_box.depth = src_box.depth; + + /* Don't copy to device memory of managed resources. + * We don't want to download it back again later. + */ + if (This->desc.Pool == D3DPOOL_MANAGED) + r_dst = NULL; + + /* Don't copy from stale device memory of managed resources. + * Also, don't copy between system and device if we don't have to. + */ + if (From->desc.Pool == D3DPOOL_MANAGED) { + if (!r_dst || NineVolume9_IsDirty(From)) + r_src = NULL; + } + + if (r_dst && r_src) { + pipe->resource_copy_region(pipe, + r_dst, This->level, + dst_box.x, dst_box.y, dst_box.z, + r_src, From->level, + &src_box); + } else + if (r_dst) { + p_src = NineVolume9_GetSystemMemPointer(From, + src_box.x, src_box.y, src_box.z); + + pipe->transfer_inline_write(pipe, r_dst, This->level, + 0, /* WRITE|DISCARD are implicit */ + &dst_box, p_src, + From->stride, From->layer_stride); + } else + if (r_src) { + p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); + p_src = pipe->transfer_map(pipe, r_src, From->level, + PIPE_TRANSFER_READ, + &src_box, &transfer); + if (!p_src) + return D3DERR_DRIVERINTERNALERROR; + + util_copy_box(p_dst, This->info.format, + This->stride, This->layer_stride, + dst_box.x, dst_box.y, dst_box.z, + dst_box.width, dst_box.height, dst_box.depth, + p_src, + transfer->stride, transfer->layer_stride, + src_box.x, src_box.y, src_box.z); + + pipe->transfer_unmap(pipe, transfer); + } else { + p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); + p_src = NineVolume9_GetSystemMemPointer(From, 0, 0, 0); + + util_copy_box(p_dst, This->info.format, + This->stride, This->layer_stride, + dst_box.x, dst_box.y, dst_box.z, + dst_box.width, dst_box.height, dst_box.depth, + p_src, + From->stride, From->layer_stride, + src_box.x, src_box.y, src_box.z); + } + + if (This->desc.Pool == D3DPOOL_DEFAULT || + This->desc.Pool == D3DPOOL_MANAGED) + NineVolume9_MarkContainerDirty(This); + if (!r_dst && This->resource) + NineVolume9_AddDirtyRegion(This, &dst_box); + + return D3D_OK; +} + +HRESULT +NineVolume9_UploadSelf( struct NineVolume9 *This ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *res = This->resource; + uint8_t *ptr; + unsigned i; + + DBG("This=%p dirty=%i data=%p res=%p\n", This, NineVolume9_IsDirty(This), + This->data, res); + + assert(This->desc.Pool == D3DPOOL_MANAGED); + + if (!NineVolume9_IsDirty(This)) + return D3D_OK; + assert(res); + + for (i = 0; i < Elements(This->dirty_box); ++i) { + const struct pipe_box *box = &This->dirty_box[i]; + if (box->width == 0) + break; + ptr = NineVolume9_GetSystemMemPointer(This, box->x, box->y, box->z); + + pipe->transfer_inline_write(pipe, res, This->level, + 0, + box, ptr, This->stride, This->layer_stride); + } + NineVolume9_ClearDirtyRegion(This); + + return D3D_OK; +} + + +IDirect3DVolume9Vtbl NineVolume9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */ + (void *)NineVolume9_SetPrivateData, + (void *)NineVolume9_GetPrivateData, + (void *)NineVolume9_FreePrivateData, + (void *)NineVolume9_GetContainer, + (void *)NineVolume9_GetDesc, + (void *)NineVolume9_LockBox, + (void *)NineVolume9_UnlockBox +}; + +static const GUID *NineVolume9_IIDs[] = { + &IID_IDirect3DVolume9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineVolume9_new( struct NineDevice9 *pDevice, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + unsigned Level, + D3DVOLUME_DESC *pDesc, + struct NineVolume9 **ppOut ) +{ + NINE_DEVICE_CHILD_NEW(Volume9, ppOut, pDevice, /* args */ + pContainer, pResource, Level, pDesc); +} + + +/*** The boring stuff. TODO: Unify with Resource. ***/ + +HRESULT WINAPI +NineVolume9_SetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ) +{ + enum pipe_error err; + struct pheader *header; + const void *user_data = pData; + + if (Flags & D3DSPD_IUNKNOWN) + user_assert(SizeOfData == sizeof(IUnknown *), D3DERR_INVALIDCALL); + + /* data consists of a header and the actual data. avoiding 2 mallocs */ + header = CALLOC_VARIANT_LENGTH_STRUCT(pheader, SizeOfData-1); + if (!header) { return E_OUTOFMEMORY; } + header->unknown = (Flags & D3DSPD_IUNKNOWN) ? TRUE : FALSE; + + /* if the refguid already exists, delete it */ + NineVolume9_FreePrivateData(This, refguid); + + /* IUnknown special case */ + if (header->unknown) { + /* here the pointer doesn't point to the data we want, so point at the + * pointer making what we eventually copy is the pointer itself */ + user_data = &pData; + } + + header->size = SizeOfData; + memcpy(header->data, user_data, header->size); + + err = util_hash_table_set(This->pdata, refguid, header); + if (err == PIPE_OK) { + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); } + return D3D_OK; + } + + FREE(header); + if (err == PIPE_ERROR_OUT_OF_MEMORY) { return E_OUTOFMEMORY; } + + return D3DERR_DRIVERINTERNALERROR; +} + +HRESULT WINAPI +NineVolume9_GetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ) +{ + struct pheader *header; + + user_assert(pSizeOfData, E_POINTER); + + header = util_hash_table_get(This->pdata, refguid); + if (!header) { return D3DERR_NOTFOUND; } + + if (!pData) { + *pSizeOfData = header->size; + return D3D_OK; + } + if (*pSizeOfData < header->size) { + return D3DERR_MOREDATA; + } + + if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); } + memcpy(pData, header->data, header->size); + + return D3D_OK; +} + +HRESULT WINAPI +NineVolume9_FreePrivateData( struct NineVolume9 *This, + REFGUID refguid ) +{ + struct pheader *header; + + header = util_hash_table_get(This->pdata, refguid); + if (!header) { return D3DERR_NOTFOUND; } + + ht_guid_delete(NULL, header, NULL); + util_hash_table_remove(This->pdata, refguid); + + return D3D_OK; +} + diff --git a/src/gallium/state_trackers/nine/volume9.h b/src/gallium/state_trackers/nine/volume9.h new file mode 100644 index 00000000000..802836659c2 --- /dev/null +++ b/src/gallium/state_trackers/nine/volume9.h @@ -0,0 +1,141 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_VOLUME9_H_ +#define _NINE_VOLUME9_H_ + +#include "iunknown.h" + +#include "pipe/p_state.h" +#include "util/u_inlines.h" + +struct util_hash_table; + +struct NineDevice9; + +struct NineVolume9 +{ + struct NineUnknown base; + + struct pipe_resource *resource; + unsigned level; + unsigned level_actual; + + uint8_t *data; /* system memory backing */ + + D3DVOLUME_DESC desc; + struct pipe_resource info; + unsigned stride; + unsigned layer_stride; + + struct pipe_transfer *transfer; + unsigned lock_count; + + struct pipe_box dirty_box[2]; + + struct pipe_context *pipe; + + /* for [GS]etPrivateData/FreePrivateData */ + struct util_hash_table *pdata; +}; +static INLINE struct NineVolume9 * +NineVolume9( void *data ) +{ + return (struct NineVolume9 *)data; +} + +HRESULT +NineVolume9_new( struct NineDevice9 *pDevice, + struct NineUnknown *pContainer, + struct pipe_resource *pResource, + unsigned Level, + D3DVOLUME_DESC *pDesc, + struct NineVolume9 **ppOut ); + +/*** Nine private ***/ + +static INLINE void +NineVolume9_SetResource( struct NineVolume9 *This, + struct pipe_resource *resource, unsigned level ) +{ + This->level = level; + pipe_resource_reference(&This->resource, resource); +} + +void +NineVolume9_AddDirtyRegion( struct NineVolume9 *This, + const struct pipe_box *box ); + +static INLINE void +NineVolume9_ClearDirtyRegion( struct NineVolume9 *This ) +{ + memset(&This->dirty_box, 0, sizeof(This->dirty_box)); +} + +HRESULT +NineVolume9_CopyVolume( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ); + +HRESULT +NineVolume9_UploadSelf( struct NineVolume9 *This ); + + +/*** Direct3D public ***/ + +HRESULT WINAPI +NineVolume9_SetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + const void *pData, + DWORD SizeOfData, + DWORD Flags ); + +HRESULT WINAPI +NineVolume9_GetPrivateData( struct NineVolume9 *This, + REFGUID refguid, + void *pData, + DWORD *pSizeOfData ); + +HRESULT WINAPI +NineVolume9_FreePrivateData( struct NineVolume9 *This, + REFGUID refguid ); + +HRESULT WINAPI +NineVolume9_GetContainer( struct NineVolume9 *This, + REFIID riid, + void **ppContainer ); + +HRESULT WINAPI +NineVolume9_GetDesc( struct NineVolume9 *This, + D3DVOLUME_DESC *pDesc ); + +HRESULT WINAPI +NineVolume9_LockBox( struct NineVolume9 *This, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ); + +HRESULT WINAPI +NineVolume9_UnlockBox( struct NineVolume9 *This ); + +#endif /* _NINE_VOLUME9_H_ */ diff --git a/src/gallium/state_trackers/nine/volumetexture9.c b/src/gallium/state_trackers/nine/volumetexture9.c new file mode 100644 index 00000000000..65d320c6645 --- /dev/null +++ b/src/gallium/state_trackers/nine/volumetexture9.c @@ -0,0 +1,253 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "device9.h" +#include "volumetexture9.h" +#include "nine_helpers.h" +#include "nine_pipe.h" + +#define DBG_CHANNEL DBG_VOLUMETEXTURE + +static HRESULT +NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This, + struct NineUnknownParams *pParams, + UINT Width, UINT Height, UINT Depth, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + HANDLE *pSharedHandle ) +{ + struct pipe_resource *info = &This->base.base.info; + unsigned l; + D3DVOLUME_DESC voldesc; + HRESULT hr; + + /* An IDirect3DVolume9 cannot be bound as a render target can it ? */ + user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)), + D3DERR_INVALIDCALL); + user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || + (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); + + user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */ + + if (Usage & D3DUSAGE_AUTOGENMIPMAP) + Levels = 0; + + This->base.format = Format; + This->base.base.usage = Usage; + + info->screen = pParams->device->screen; + info->target = PIPE_TEXTURE_3D; + info->format = d3d9_to_pipe_format(Format); + info->width0 = Width; + info->height0 = Height; + info->depth0 = Depth; + if (Levels) + info->last_level = Levels - 1; + else + info->last_level = util_logbase2(MAX2(MAX2(Width, Height), Depth)); + info->array_size = 1; + info->nr_samples = 0; + info->bind = PIPE_BIND_SAMPLER_VIEW; + info->usage = PIPE_USAGE_DEFAULT; + info->flags = 0; + + if (Usage & D3DUSAGE_DYNAMIC) { + info->usage = PIPE_USAGE_DYNAMIC; + info->bind |= + PIPE_BIND_TRANSFER_READ | + PIPE_BIND_TRANSFER_WRITE; + } + + This->volumes = CALLOC(info->last_level + 1, sizeof(*This->volumes)); + if (!This->volumes) + return E_OUTOFMEMORY; + This->base.pstype = 3; + + hr = NineBaseTexture9_ctor(&This->base, pParams, + D3DRTYPE_VOLUMETEXTURE, Pool); + if (FAILED(hr)) + return hr; + + voldesc.Format = Format; + voldesc.Type = D3DRTYPE_VOLUME; + voldesc.Usage = Usage; + voldesc.Pool = Pool; + for (l = 0; l <= info->last_level; ++l) { + voldesc.Width = u_minify(Width, l); + voldesc.Height = u_minify(Height, l); + voldesc.Depth = u_minify(Depth, l); + + hr = NineVolume9_new(This->base.base.base.device, NineUnknown(This), + This->base.base.resource, l, + &voldesc, &This->volumes[l]); + if (FAILED(hr)) + return hr; + } + + return D3D_OK; +} + +static void +NineVolumeTexture9_dtor( struct NineVolumeTexture9 *This ) +{ + unsigned l; + + DBG("This=%p\n", This); + + if (This->volumes) { + for (l = 0; l < This->base.base.info.last_level; ++l) + NineUnknown_Destroy(&This->volumes[l]->base); + FREE(This->volumes); + } + + NineBaseTexture9_dtor(&This->base); +} + +HRESULT WINAPI +NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + *pDesc = This->volumes[Level]->desc; + + return D3D_OK; +} + +HRESULT WINAPI +NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + NineUnknown_AddRef(NineUnknown(This->volumes[Level])); + *ppVolumeLevel = (IDirect3DVolume9 *)This->volumes[Level]; + + return D3D_OK; +} + +HRESULT WINAPI +NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), + D3DERR_INVALIDCALL); + + return NineVolume9_LockBox(This->volumes[Level], pLockedVolume, pBox, + Flags); +} + +HRESULT WINAPI +NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ) +{ + user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); + + return NineVolume9_UnlockBox(This->volumes[Level]); +} + +HRESULT WINAPI +NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ) +{ + if (This->base.base.pool != D3DPOOL_MANAGED) { + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) + This->base.dirty_mip = TRUE; + return D3D_OK; + } + This->base.dirty = TRUE; + + BASETEX_REGISTER_UPDATE(&This->base); + + if (!pDirtyBox) { + This->dirty_box.x = 0; + This->dirty_box.y = 0; + This->dirty_box.z = 0; + This->dirty_box.width = This->base.base.info.width0; + This->dirty_box.height = This->base.base.info.height0; + This->dirty_box.depth = This->base.base.info.depth0; + } else { + struct pipe_box box; + d3dbox_to_pipe_box(&box, pDirtyBox); + u_box_union_3d(&This->dirty_box, &This->dirty_box, &box); + } + return D3D_OK; +} + +IDirect3DVolumeTexture9Vtbl NineVolumeTexture9_vtable = { + (void *)NineUnknown_QueryInterface, + (void *)NineUnknown_AddRef, + (void *)NineUnknown_Release, + (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ + (void *)NineResource9_SetPrivateData, + (void *)NineResource9_GetPrivateData, + (void *)NineResource9_FreePrivateData, + (void *)NineResource9_SetPriority, + (void *)NineResource9_GetPriority, + (void *)NineBaseTexture9_PreLoad, + (void *)NineResource9_GetType, + (void *)NineBaseTexture9_SetLOD, + (void *)NineBaseTexture9_GetLOD, + (void *)NineBaseTexture9_GetLevelCount, + (void *)NineBaseTexture9_SetAutoGenFilterType, + (void *)NineBaseTexture9_GetAutoGenFilterType, + (void *)NineBaseTexture9_GenerateMipSubLevels, + (void *)NineVolumeTexture9_GetLevelDesc, + (void *)NineVolumeTexture9_GetVolumeLevel, + (void *)NineVolumeTexture9_LockBox, + (void *)NineVolumeTexture9_UnlockBox, + (void *)NineVolumeTexture9_AddDirtyBox +}; + +static const GUID *NineVolumeTexture9_IIDs[] = { + &IID_IDirect3DVolumeTexture9, + &IID_IDirect3DBaseTexture9, + &IID_IDirect3DResource9, + &IID_IUnknown, + NULL +}; + +HRESULT +NineVolumeTexture9_new( struct NineDevice9 *pDevice, + UINT Width, UINT Height, UINT Depth, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineVolumeTexture9 **ppOut, + HANDLE *pSharedHandle ) +{ + NINE_DEVICE_CHILD_NEW(VolumeTexture9, ppOut, pDevice, + Width, Height, Depth, Levels, + Usage, Format, Pool, pSharedHandle); +} + diff --git a/src/gallium/state_trackers/nine/volumetexture9.h b/src/gallium/state_trackers/nine/volumetexture9.h new file mode 100644 index 00000000000..313fa1a91fb --- /dev/null +++ b/src/gallium/state_trackers/nine/volumetexture9.h @@ -0,0 +1,75 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _NINE_VOLUMETEXTURE9_H_ +#define _NINE_VOLUMETEXTURE9_H_ + +#include "basetexture9.h" +#include "volume9.h" + +struct NineVolumeTexture9 +{ + struct NineBaseTexture9 base; + struct NineVolume9 **volumes; + struct pipe_box dirty_box; +}; +static INLINE struct NineVolumeTexture9 * +NineVolumeTexture9( void *data ) +{ + return (struct NineVolumeTexture9 *)data; +} + +HRESULT +NineVolumeTexture9_new( struct NineDevice9 *pDevice, + UINT Width, UINT Height, UINT Depth, UINT Levels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + struct NineVolumeTexture9 **ppOut, + HANDLE *pSharedHandle ); + +HRESULT WINAPI +NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This, + UINT Level, + D3DVOLUME_DESC *pDesc ); + +HRESULT WINAPI +NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This, + UINT Level, + IDirect3DVolume9 **ppVolumeLevel ); + +HRESULT WINAPI +NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This, + UINT Level, + D3DLOCKED_BOX *pLockedVolume, + const D3DBOX *pBox, + DWORD Flags ); + +HRESULT WINAPI +NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This, + UINT Level ); + +HRESULT WINAPI +NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, + const D3DBOX *pDirtyBox ); + +#endif /* _NINE_VOLUMETEXTURE9_H_ */ diff --git a/src/gallium/targets/d3dadapter9/Makefile.am b/src/gallium/targets/d3dadapter9/Makefile.am new file mode 100644 index 00000000000..62312369adc --- /dev/null +++ b/src/gallium/targets/d3dadapter9/Makefile.am @@ -0,0 +1,131 @@ +# Copyright © 2012 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + -I$(top_srcdir)/include/D3D9 \ + -I$(top_srcdir)/src/loader \ + -I$(top_srcdir)/src/mapi/ \ + -I$(top_srcdir)/src/mesa/ \ + -I$(top_srcdir)/src/mesa/drivers/dri/common/ \ + -I$(top_builddir)/src/mesa/drivers/dri/common/ \ + -I$(top_srcdir)/src/gallium/winsys \ + -I$(top_srcdir)/src/gallium/state_trackers/nine \ + $(GALLIUM_TARGET_CFLAGS) \ + $(VISIBILITY_CFLAGS) + +if HAVE_GALLIUM_STATIC_TARGETS +AM_CPPFLAGS = \ + -DNINE_TARGET \ + -DGALLIUM_STATIC_TARGETS=1 + +else + +AM_CPPFLAGS = \ + -DPIPE_SEARCH_DIR=\"$(libdir)/gallium-pipe\" \ + $(GALLIUM_PIPE_LOADER_DEFINES) + +endif + +ninedir = $(D3D_DRIVER_INSTALL_DIR) +nine_LTLIBRARIES = d3dadapter9.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = d3d.pc + +d3dadapter9_la_SOURCES = \ + getproc.c \ + drm.c + +d3dadapter9_la_LDFLAGS = \ + -shared \ + -shrext .so \ + -module \ + -no-undefined \ + -version-number $(NINE_MAJOR):$(NINE_MINOR) \ + $(GC_SECTIONS) \ + $(LD_NO_UNDEFINED) + +if HAVE_LD_VERSION_SCRIPT +d3dadapter9_la_LDFLAGS += \ + -Wl,--version-script=$(top_srcdir)/src/gallium/targets/d3dadapter9/d3dadapter9.sym +endif # HAVE_LD_VERSION_SCRIPT + +d3dadapter9_la_LIBADD = \ + $(top_builddir)/src/gallium/auxiliary/libgallium.la \ + $(top_builddir)/src/gallium/state_trackers/nine/libninetracker.la \ + $(top_builddir)/src/util/libmesautil.la \ + $(top_builddir)/src/gallium/winsys/sw/wrapper/libwsw.la \ + $(EXPAT_LIBS) \ + $(GALLIUM_COMMON_LIB_DEPS) + + +TARGET_DRIVERS = +TARGET_CPPFLAGS = +TARGET_LIB_DEPS = $(top_builddir)/src/loader/libloader.la + +include $(top_srcdir)/src/gallium/drivers/i915/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/ilo/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/nouveau/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/r300/Automake.inc +include $(top_srcdir)/src/gallium/drivers/r600/Automake.inc +include $(top_srcdir)/src/gallium/drivers/radeonsi/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/svga/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/freedreno/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc + +include $(top_srcdir)/src/gallium/drivers/softpipe/Automake.inc +include $(top_srcdir)/src/gallium/drivers/llvmpipe/Automake.inc + +if HAVE_GALLIUM_STATIC_TARGETS + +d3dadapter9_la_CPPFLAGS = $(AM_CPPFLAGS) $(TARGET_CPPFLAGS) +d3dadapter9_la_LIBADD += $(TARGET_LIB_DEPS) \ + $(TARGET_RADEON_WINSYS) $(TARGET_RADEON_COMMON) + +else # HAVE_GALLIUM_STATIC_TARGETS + +d3dadapter9_la_LIBADD += \ + $(top_builddir)/src/gallium/auxiliary/pipe-loader/libpipe_loader.la \ + $(GALLIUM_PIPE_LOADER_WINSYS_LIBS) \ + $(GALLIUM_PIPE_LOADER_LIBS) + +endif # HAVE_GALLIUM_STATIC_TARGETS + +if HAVE_MESA_LLVM +nodist_EXTRA_d3dadapter9_la_SOURCES = dummy.cpp +d3dadapter9_la_LDFLAGS += $(LLVM_LDFLAGS) +d3dadapter9_la_LIBADD += $(LLVM_LIBS) +endif + +d3dadapterdir = $(includedir)/d3dadapter +d3dadapter_HEADERS = \ + $(top_srcdir)/include/d3dadapter/d3dadapter9.h \ + $(top_srcdir)/include/d3dadapter/drm.h \ + $(top_srcdir)/include/d3dadapter/present.h diff --git a/src/gallium/targets/d3dadapter9/d3d.pc.in b/src/gallium/targets/d3dadapter9/d3d.pc.in new file mode 100644 index 00000000000..9a18a5c1b8e --- /dev/null +++ b/src/gallium/targets/d3dadapter9/d3d.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +moduledir=@D3D_DRIVER_INSTALL_DIR@ + +Name: d3d +Description: Native D3D driver modules +Version: @VERSION@ +Requires.private: @DRI_PC_REQ_PRIV@ +Cflags: -I${includedir} diff --git a/src/gallium/targets/d3dadapter9/d3dadapter9.sym b/src/gallium/targets/d3dadapter9/d3dadapter9.sym new file mode 100644 index 00000000000..2290daea7a3 --- /dev/null +++ b/src/gallium/targets/d3dadapter9/d3dadapter9.sym @@ -0,0 +1,6 @@ +{ + global: + D3DAdapter9GetProc; + local: + *; +}; diff --git a/src/gallium/targets/d3dadapter9/drm.c b/src/gallium/targets/d3dadapter9/drm.c new file mode 100644 index 00000000000..d0b72e07bc2 --- /dev/null +++ b/src/gallium/targets/d3dadapter9/drm.c @@ -0,0 +1,327 @@ +/* + * Copyright 2011 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "loader.h" + +#include "adapter9.h" + +#include "pipe-loader/pipe_loader.h" + +#include "pipe/p_screen.h" +#include "pipe/p_state.h" + +#include "target-helpers/inline_drm_helper.h" +#include "target-helpers/inline_sw_helper.h" +#include "state_tracker/drm_driver.h" + +#include "d3dadapter/d3dadapter9.h" +#include "d3dadapter/drm.h" + +#include <libdrm/drm.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <stdio.h> + +#define DBG_CHANNEL DBG_ADAPTER + +#define VERSION_DWORD(hi, lo) \ + ((DWORD)( \ + ((DWORD)((hi) & 0xFFFF) << 16) | \ + (DWORD)((lo) & 0xFFFF) \ + )) + +/* Regarding os versions, we should not define our own as that would simply be + * weird. Defaulting to Win2k/XP seems sane considering the origin of D3D9. The + * driver also defaults to being a generic D3D9 driver, which of course only + * matters if you're actually using the DDI. */ +#define VERSION_HIGH VERSION_DWORD(0x0006, 0x000E) /* winxp, d3d9 */ +#define VERSION_LOW VERSION_DWORD(0x0000, 0x0001) /* version, build */ + +struct d3dadapter9drm_context +{ + struct d3dadapter9_context base; + struct pipe_loader_device *dev, *swdev; +}; + +static void +drm_destroy( struct d3dadapter9_context *ctx ) +{ +#if !GALLIUM_STATIC_TARGETS + struct d3dadapter9drm_context *drm = (struct d3dadapter9drm_context *)ctx; + + /* pipe_loader_sw destroys the context */ + if (drm->swdev) + pipe_loader_release(&drm->swdev, 1); + if (drm->dev) + pipe_loader_release(&drm->dev, 1); +#endif + + FREE(ctx); +} + +/* read a DWORD in the form 0xnnnnnnnn, which is how sysfs pci id stuff is + * formatted. */ +static INLINE DWORD +read_file_dword( const char *name ) +{ + char buf[32]; + int fd, r; + + fd = open(name, O_RDONLY); + if (fd < 0) { + DBG("Unable to get PCI information from `%s'\n", name); + return 0; + } + + r = read(fd, buf, 32); + close(fd); + + return (r > 0) ? (DWORD)strtol(buf, NULL, 0) : 0; +} + +/* sysfs doesn't expose the revision as its own file, so this function grabs a + * dword at an offset in the raw PCI header. The reason this isn't used for all + * data is that the kernel will make corrections but not expose them in the raw + * header bytes. */ +static INLINE DWORD +read_config_dword( int fd, + unsigned offset ) +{ + DWORD r = 0; + + if (lseek(fd, offset, SEEK_SET) != offset) { return 0; } + if (read(fd, &r, 4) != 4) { return 0; } + + return r; +} + +static INLINE void +get_bus_info( int fd, + DWORD *vendorid, + DWORD *deviceid, + DWORD *subsysid, + DWORD *revision ) +{ + drm_unique_t u; + + u.unique_len = 0; + u.unique = NULL; + + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { return; } + u.unique = CALLOC(u.unique_len+1, 1); + + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { return; } + u.unique[u.unique_len] = '\0'; + + DBG("DRM Device BusID: %s\n", u.unique); + if (strncmp("pci:", u.unique, 4) == 0) { + char fname[512]; /* this ought to be enough */ + int l = snprintf(fname, 512, "/sys/bus/pci/devices/%s/", u.unique+4); + + /* VendorId */ + snprintf(fname+l, 512-l, "vendor"); + *vendorid = read_file_dword(fname); + /* DeviceId */ + snprintf(fname+l, 512-l, "device"); + *deviceid = read_file_dword(fname); + /* SubSysId */ + snprintf(fname+l, 512-l, "subsystem_device"); + *subsysid = (read_file_dword(fname) << 16) & 0xFFFF0000; + snprintf(fname+l, 512-l, "subsystem_vendor"); + *subsysid |= read_file_dword(fname) & 0x0000FFFF; + /* Revision */ + { + int cfgfd; + + snprintf(fname+l, 512-l, "config"); + cfgfd = open(fname, O_RDONLY); + if (cfgfd >= 0) { + *revision = read_config_dword(cfgfd, 0x8) & 0x000000FF; + close(cfgfd); + } else { + DBG("Unable to get raw PCI information from `%s'\n", fname); + } + } + DBG("PCI info: vendor=0x%04x, device=0x%04x, subsys=0x%08x, rev=%d\n", + *vendorid, *deviceid, *subsysid, *revision); + } else { + DBG("Unsupported BusID type.\n"); + } + + FREE(u.unique); +} + +static INLINE void +read_descriptor( struct d3dadapter9_context *ctx, + int fd ) +{ + D3DADAPTER_IDENTIFIER9 *drvid = &ctx->identifier; + + memset(drvid, 0, sizeof(*drvid)); + get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId, + &drvid->SubSysId, &drvid->Revision); + + strncpy(drvid->Driver, "libd3dadapter9.so", sizeof(drvid->Driver)); + strncpy(drvid->DeviceName, ctx->hal->get_name(ctx->hal), 32); + snprintf(drvid->Description, sizeof(drvid->Description), + "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal)); + + drvid->DriverVersionLowPart = VERSION_LOW; + drvid->DriverVersionHighPart = VERSION_HIGH; + + /* To make a pseudo-real GUID we use the PCI bus data and some string */ + drvid->DeviceIdentifier.Data1 = drvid->VendorId; + drvid->DeviceIdentifier.Data2 = drvid->DeviceId; + drvid->DeviceIdentifier.Data3 = drvid->SubSysId; + memcpy(drvid->DeviceIdentifier.Data4, "Gallium3D", 8); + + drvid->WHQLLevel = 1; /* This fakes WHQL validaion */ + + /* XXX Fake NVIDIA binary driver on Windows. + * + * OS version: 4=95/98/NT4, 5=2000, 6=2000/XP, 7=Vista, 8=Win7 + */ + strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver)); + strncpy(drvid->Description, "NVIDIA GeForce GTX 680", sizeof(drvid->Description)); + drvid->DriverVersionLowPart = VERSION_DWORD(12, 6658); /* minor, build */ + drvid->DriverVersionHighPart = VERSION_DWORD(6, 15); /* OS, major */ + drvid->SubSysId = 0; + drvid->Revision = 0; + drvid->DeviceIdentifier.Data1 = 0xaeb2cdd4; + drvid->DeviceIdentifier.Data2 = 0x6e41; + drvid->DeviceIdentifier.Data3 = 0x43ea; + drvid->DeviceIdentifier.Data4[0] = 0x94; + drvid->DeviceIdentifier.Data4[1] = 0x1c; + drvid->DeviceIdentifier.Data4[2] = 0x83; + drvid->DeviceIdentifier.Data4[3] = 0x61; + drvid->DeviceIdentifier.Data4[4] = 0xcc; + drvid->DeviceIdentifier.Data4[5] = 0x76; + drvid->DeviceIdentifier.Data4[6] = 0x07; + drvid->DeviceIdentifier.Data4[7] = 0x81; + drvid->WHQLLevel = 0; +} + +static HRESULT WINAPI +drm_create_adapter( int fd, + ID3DAdapter9 **ppAdapter ) +{ + struct d3dadapter9drm_context *ctx = CALLOC_STRUCT(d3dadapter9drm_context); + HRESULT hr; + int i, different_device; + const struct drm_conf_ret *throttle_ret = NULL; + const struct drm_conf_ret *dmabuf_ret = NULL; + +#if !GALLIUM_STATIC_TARGETS + const char *paths[] = { + getenv("D3D9_DRIVERS_PATH"), + getenv("D3D9_DRIVERS_DIR"), + PIPE_SEARCH_DIR + }; +#endif + + if (!ctx) { return E_OUTOFMEMORY; } + + ctx->base.destroy = drm_destroy; + + fd = loader_get_user_preferred_fd(fd, &different_device); + ctx->base.linear_framebuffer = !!different_device; + +#if GALLIUM_STATIC_TARGETS + ctx->base.hal = dd_create_screen(fd); +#else + /* use pipe-loader to dlopen appropriate drm driver */ + if (!pipe_loader_drm_probe_fd(&ctx->dev, fd, FALSE)) { + ERR("Failed to probe drm fd %d.\n", fd); + FREE(ctx); + close(fd); + return D3DERR_DRIVERINTERNALERROR; + } + + /* use pipe-loader to create a drm screen (hal) */ + ctx->base.hal = NULL; + for (i = 0; !ctx->base.hal && i < Elements(paths); ++i) { + if (!paths[i]) { continue; } + ctx->base.hal = pipe_loader_create_screen(ctx->dev, paths[i]); + } +#endif + if (!ctx->base.hal) { + ERR("Unable to load requested driver.\n"); + drm_destroy(&ctx->base); + return D3DERR_DRIVERINTERNALERROR; + } + +#if GALLIUM_STATIC_TARGETS + dmabuf_ret = dd_configuration(DRM_CONF_SHARE_FD); + throttle_ret = dd_configuration(DRM_CONF_THROTTLE); +#else + dmabuf_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_SHARE_FD); + throttle_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_THROTTLE); +#endif // GALLIUM_STATIC_TARGETS + if (!dmabuf_ret || !dmabuf_ret->val.val_bool) { + ERR("The driver is not capable of dma-buf sharing." + "Abandon to load nine state tracker\n"); + drm_destroy(&ctx->base); + return D3DERR_DRIVERINTERNALERROR; + } + + if (throttle_ret && throttle_ret->val.val_int != -1) { + ctx->base.throttling = TRUE; + ctx->base.throttling_value = throttle_ret->val.val_int; + } else + ctx->base.throttling = FALSE; + + +#if GALLIUM_STATIC_TARGETS + ctx->base.ref = ninesw_create_screen(ctx->base.hal); +#else + /* wrap it to create a software screen that can share resources */ + if (pipe_loader_sw_probe_wrapped(&ctx->swdev, ctx->base.hal)) { + ctx->base.ref = NULL; + for (i = 0; !ctx->base.ref && i < Elements(paths); ++i) { + if (!paths[i]) { continue; } + ctx->base.ref = pipe_loader_create_screen(ctx->swdev, paths[i]); + } + } +#endif + if (!ctx->base.ref) { + ERR("Couldn't wrap drm screen to swrast screen. Software devices " + "will be unavailable.\n"); + } + + /* read out PCI info */ + read_descriptor(&ctx->base, fd); + + /* create and return new ID3DAdapter9 */ + hr = NineAdapter9_new(&ctx->base, (struct NineAdapter9 **)ppAdapter); + if (FAILED(hr)) { + drm_destroy(&ctx->base); + return hr; + } + + return D3D_OK; +} + +const struct D3DAdapter9DRM drm9_desc = { + .major_version = D3DADAPTER9DRM_MAJOR, + .minor_version = D3DADAPTER9DRM_MINOR, + .create_adapter = drm_create_adapter +}; diff --git a/src/gallium/targets/d3dadapter9/getproc.c b/src/gallium/targets/d3dadapter9/getproc.c new file mode 100644 index 00000000000..2aa79a444ed --- /dev/null +++ b/src/gallium/targets/d3dadapter9/getproc.c @@ -0,0 +1,47 @@ +/* + * Copyright 2013 Joakim Sindholt <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include <string.h> + +#include "util/u_memory.h" + +#include "d3dadapter/drm.h" +extern const struct D3DAdapter9DRM drm9_desc; + +struct { + const char *name; + const void *desc; +} drivers[] = { + { D3DADAPTER9DRM_NAME, &drm9_desc }, +}; + +PUBLIC const void * WINAPI +D3DAdapter9GetProc( const char *name ) +{ + int i; + for (i = 0; i < Elements(drivers); ++i) { + if (strcmp(name, drivers[i].name) == 0) { + return drivers[i].desc; + } + } + return NULL; +} |