947 lines
28 KiB
C
947 lines
28 KiB
C
/*
|
|
* Copyright 2013 Henri Verbeet for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "wine/port.h"
|
|
#include "wined3d_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
|
|
|
#define WINED3D_INITIAL_CS_SIZE 4096
|
|
|
|
enum wined3d_cs_op
|
|
{
|
|
WINED3D_CS_OP_PRESENT,
|
|
WINED3D_CS_OP_CLEAR,
|
|
WINED3D_CS_OP_DRAW,
|
|
WINED3D_CS_OP_SET_VIEWPORT,
|
|
WINED3D_CS_OP_SET_SCISSOR_RECT,
|
|
WINED3D_CS_OP_SET_RENDER_TARGET,
|
|
WINED3D_CS_OP_SET_DEPTH_STENCIL,
|
|
WINED3D_CS_OP_SET_VERTEX_DECLARATION,
|
|
WINED3D_CS_OP_SET_STREAM_SOURCE,
|
|
WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ,
|
|
WINED3D_CS_OP_SET_STREAM_OUTPUT,
|
|
WINED3D_CS_OP_SET_INDEX_BUFFER,
|
|
WINED3D_CS_OP_SET_CONSTANT_BUFFER,
|
|
WINED3D_CS_OP_SET_TEXTURE,
|
|
WINED3D_CS_OP_SET_SAMPLER,
|
|
WINED3D_CS_OP_SET_SHADER,
|
|
WINED3D_CS_OP_SET_RENDER_STATE,
|
|
WINED3D_CS_OP_SET_TEXTURE_STATE,
|
|
WINED3D_CS_OP_SET_SAMPLER_STATE,
|
|
WINED3D_CS_OP_SET_TRANSFORM,
|
|
WINED3D_CS_OP_SET_CLIP_PLANE,
|
|
WINED3D_CS_OP_SET_MATERIAL,
|
|
WINED3D_CS_OP_RESET_STATE,
|
|
};
|
|
|
|
struct wined3d_cs_present
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
HWND dst_window_override;
|
|
struct wined3d_swapchain *swapchain;
|
|
const RECT *src_rect;
|
|
const RECT *dst_rect;
|
|
const RGNDATA *dirty_region;
|
|
DWORD flags;
|
|
};
|
|
|
|
struct wined3d_cs_clear
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
DWORD rect_count;
|
|
const RECT *rects;
|
|
DWORD flags;
|
|
const struct wined3d_color *color;
|
|
float depth;
|
|
DWORD stencil;
|
|
};
|
|
|
|
struct wined3d_cs_draw
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT start_idx;
|
|
UINT index_count;
|
|
UINT start_instance;
|
|
UINT instance_count;
|
|
BOOL indexed;
|
|
};
|
|
|
|
struct wined3d_cs_set_viewport
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
const struct wined3d_viewport *viewport;
|
|
};
|
|
|
|
struct wined3d_cs_set_scissor_rect
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
const RECT *rect;
|
|
};
|
|
|
|
struct wined3d_cs_set_render_target
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT render_target_idx;
|
|
struct wined3d_surface *render_target;
|
|
};
|
|
|
|
struct wined3d_cs_set_depth_stencil
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
struct wined3d_surface *depth_stencil;
|
|
};
|
|
|
|
struct wined3d_cs_set_vertex_declaration
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
struct wined3d_vertex_declaration *declaration;
|
|
};
|
|
|
|
struct wined3d_cs_set_stream_source
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT stream_idx;
|
|
struct wined3d_buffer *buffer;
|
|
UINT offset;
|
|
UINT stride;
|
|
};
|
|
|
|
struct wined3d_cs_set_stream_source_freq
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT stream_idx;
|
|
UINT frequency;
|
|
UINT flags;
|
|
};
|
|
|
|
struct wined3d_cs_set_stream_output
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT stream_idx;
|
|
struct wined3d_buffer *buffer;
|
|
UINT offset;
|
|
};
|
|
|
|
struct wined3d_cs_set_index_buffer
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
struct wined3d_buffer *buffer;
|
|
enum wined3d_format_id format_id;
|
|
};
|
|
|
|
struct wined3d_cs_set_constant_buffer
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
enum wined3d_shader_type type;
|
|
UINT cb_idx;
|
|
struct wined3d_buffer *buffer;
|
|
};
|
|
|
|
struct wined3d_cs_set_texture
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT stage;
|
|
struct wined3d_texture *texture;
|
|
};
|
|
|
|
struct wined3d_cs_set_sampler
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
enum wined3d_shader_type type;
|
|
UINT sampler_idx;
|
|
struct wined3d_sampler *sampler;
|
|
};
|
|
|
|
struct wined3d_cs_set_shader
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
enum wined3d_shader_type type;
|
|
struct wined3d_shader *shader;
|
|
};
|
|
|
|
struct wined3d_cs_set_render_state
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
enum wined3d_render_state state;
|
|
DWORD value;
|
|
};
|
|
|
|
struct wined3d_cs_set_texture_state
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT stage;
|
|
enum wined3d_texture_stage_state state;
|
|
DWORD value;
|
|
};
|
|
|
|
struct wined3d_cs_set_sampler_state
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT sampler_idx;
|
|
enum wined3d_sampler_state state;
|
|
DWORD value;
|
|
};
|
|
|
|
struct wined3d_cs_set_transform
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
enum wined3d_transform_state state;
|
|
const struct wined3d_matrix *matrix;
|
|
};
|
|
|
|
struct wined3d_cs_set_clip_plane
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
UINT plane_idx;
|
|
const struct wined3d_vec4 *plane;
|
|
};
|
|
|
|
struct wined3d_cs_set_material
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
const struct wined3d_material *material;
|
|
};
|
|
|
|
struct wined3d_cs_reset_state
|
|
{
|
|
enum wined3d_cs_op opcode;
|
|
};
|
|
|
|
static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_present *op = data;
|
|
struct wined3d_swapchain *swapchain;
|
|
|
|
swapchain = op->swapchain;
|
|
wined3d_swapchain_set_window(swapchain, op->dst_window_override);
|
|
|
|
swapchain->swapchain_ops->swapchain_present(swapchain,
|
|
op->src_rect, op->dst_rect, op->dirty_region, op->flags);
|
|
}
|
|
|
|
void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
|
|
const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
|
|
const RGNDATA *dirty_region, DWORD flags)
|
|
{
|
|
struct wined3d_cs_present *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_PRESENT;
|
|
op->dst_window_override = dst_window_override;
|
|
op->swapchain = swapchain;
|
|
op->src_rect = src_rect;
|
|
op->dst_rect = dst_rect;
|
|
op->dirty_region = dirty_region;
|
|
op->flags = flags;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_clear *op = data;
|
|
struct wined3d_device *device;
|
|
RECT draw_rect;
|
|
|
|
device = cs->device;
|
|
wined3d_get_draw_rect(&device->state, &draw_rect);
|
|
device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
|
|
&device->fb, op->rect_count, op->rects, &draw_rect, op->flags,
|
|
op->color, op->depth, op->stencil);
|
|
}
|
|
|
|
void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
|
|
DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
|
|
{
|
|
struct wined3d_cs_clear *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_CLEAR;
|
|
op->rect_count = rect_count;
|
|
op->rects = rects;
|
|
op->flags = flags;
|
|
op->color = color;
|
|
op->depth = depth;
|
|
op->stencil = stencil;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_draw *op = data;
|
|
|
|
draw_primitive(cs->device, op->start_idx, op->index_count,
|
|
op->start_instance, op->instance_count, op->indexed);
|
|
}
|
|
|
|
void wined3d_cs_emit_draw(struct wined3d_cs *cs, UINT start_idx, UINT index_count,
|
|
UINT start_instance, UINT instance_count, BOOL indexed)
|
|
{
|
|
struct wined3d_cs_draw *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_DRAW;
|
|
op->start_idx = start_idx;
|
|
op->index_count = index_count;
|
|
op->start_instance = start_instance;
|
|
op->instance_count = instance_count;
|
|
op->indexed = indexed;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_viewport *op = data;
|
|
|
|
cs->state.viewport = *op->viewport;
|
|
device_invalidate_state(cs->device, STATE_VIEWPORT);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport)
|
|
{
|
|
struct wined3d_cs_set_viewport *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
|
|
op->viewport = viewport;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_scissor_rect *op = data;
|
|
|
|
cs->state.scissor_rect = *op->rect;
|
|
device_invalidate_state(cs->device, STATE_SCISSORRECT);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect)
|
|
{
|
|
struct wined3d_cs_set_scissor_rect *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT;
|
|
op->rect = rect;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_render_target(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_render_target *op = data;
|
|
|
|
cs->state.fb->render_targets[op->render_target_idx] = op->render_target;
|
|
device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_render_target(struct wined3d_cs *cs, UINT render_target_idx,
|
|
struct wined3d_surface *render_target)
|
|
{
|
|
struct wined3d_cs_set_render_target *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_RENDER_TARGET;
|
|
op->render_target_idx = render_target_idx;
|
|
op->render_target = render_target;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_depth_stencil(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_depth_stencil *op = data;
|
|
struct wined3d_device *device = cs->device;
|
|
struct wined3d_surface *prev;
|
|
|
|
if ((prev = cs->state.fb->depth_stencil))
|
|
{
|
|
if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
|
|
|| prev->flags & SFLAG_DISCARD)
|
|
{
|
|
surface_modify_ds_location(prev, WINED3D_LOCATION_DISCARDED,
|
|
prev->resource.width, prev->resource.height);
|
|
if (prev == device->onscreen_depth_stencil)
|
|
{
|
|
wined3d_surface_decref(device->onscreen_depth_stencil);
|
|
device->onscreen_depth_stencil = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
cs->fb.depth_stencil = op->depth_stencil;
|
|
|
|
if (!prev != !op->depth_stencil)
|
|
{
|
|
/* Swapping NULL / non NULL depth stencil affects the depth and tests */
|
|
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
|
|
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
|
|
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
|
|
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
|
|
}
|
|
else if (prev && prev->resource.format->depth_size != op->depth_stencil->resource.format->depth_size)
|
|
{
|
|
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
|
|
}
|
|
|
|
device_invalidate_state(device, STATE_FRAMEBUFFER);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_depth_stencil(struct wined3d_cs *cs, struct wined3d_surface *depth_stencil)
|
|
{
|
|
struct wined3d_cs_set_depth_stencil *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL;
|
|
op->depth_stencil = depth_stencil;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_vertex_declaration *op = data;
|
|
|
|
cs->state.vertex_declaration = op->declaration;
|
|
device_invalidate_state(cs->device, STATE_VDECL);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
|
|
{
|
|
struct wined3d_cs_set_vertex_declaration *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
|
|
op->declaration = declaration;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_stream_source *op = data;
|
|
struct wined3d_stream_state *stream;
|
|
struct wined3d_buffer *prev;
|
|
|
|
stream = &cs->state.streams[op->stream_idx];
|
|
prev = stream->buffer;
|
|
stream->buffer = op->buffer;
|
|
stream->offset = op->offset;
|
|
stream->stride = op->stride;
|
|
|
|
if (op->buffer)
|
|
InterlockedIncrement(&op->buffer->resource.bind_count);
|
|
if (prev)
|
|
InterlockedDecrement(&prev->resource.bind_count);
|
|
|
|
device_invalidate_state(cs->device, STATE_STREAMSRC);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
|
|
struct wined3d_buffer *buffer, UINT offset, UINT stride)
|
|
{
|
|
struct wined3d_cs_set_stream_source *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
|
|
op->stream_idx = stream_idx;
|
|
op->buffer = buffer;
|
|
op->offset = offset;
|
|
op->stride = stride;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_stream_source_freq *op = data;
|
|
struct wined3d_stream_state *stream;
|
|
|
|
stream = &cs->state.streams[op->stream_idx];
|
|
stream->frequency = op->frequency;
|
|
stream->flags = op->flags;
|
|
|
|
device_invalidate_state(cs->device, STATE_STREAMSRC);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
|
|
{
|
|
struct wined3d_cs_set_stream_source_freq *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
|
|
op->stream_idx = stream_idx;
|
|
op->frequency = frequency;
|
|
op->flags = flags;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_stream_output *op = data;
|
|
struct wined3d_stream_output *stream;
|
|
struct wined3d_buffer *prev;
|
|
|
|
stream = &cs->state.stream_output[op->stream_idx];
|
|
prev = stream->buffer;
|
|
stream->buffer = op->buffer;
|
|
stream->offset = op->offset;
|
|
|
|
if (op->buffer)
|
|
InterlockedIncrement(&op->buffer->resource.bind_count);
|
|
if (prev)
|
|
InterlockedDecrement(&prev->resource.bind_count);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
|
|
struct wined3d_buffer *buffer, UINT offset)
|
|
{
|
|
struct wined3d_cs_set_stream_output *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
|
|
op->stream_idx = stream_idx;
|
|
op->buffer = buffer;
|
|
op->offset = offset;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_index_buffer *op = data;
|
|
struct wined3d_buffer *prev;
|
|
|
|
prev = cs->state.index_buffer;
|
|
cs->state.index_buffer = op->buffer;
|
|
cs->state.index_format = op->format_id;
|
|
|
|
if (op->buffer)
|
|
InterlockedIncrement(&op->buffer->resource.bind_count);
|
|
if (prev)
|
|
InterlockedDecrement(&prev->resource.bind_count);
|
|
|
|
device_invalidate_state(cs->device, STATE_INDEXBUFFER);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
|
|
enum wined3d_format_id format_id)
|
|
{
|
|
struct wined3d_cs_set_index_buffer *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
|
|
op->buffer = buffer;
|
|
op->format_id = format_id;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_constant_buffer *op = data;
|
|
struct wined3d_buffer *prev;
|
|
|
|
prev = cs->state.cb[op->type][op->cb_idx];
|
|
cs->state.cb[op->type][op->cb_idx] = op->buffer;
|
|
|
|
if (op->buffer)
|
|
InterlockedIncrement(&op->buffer->resource.bind_count);
|
|
if (prev)
|
|
InterlockedDecrement(&prev->resource.bind_count);
|
|
|
|
device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
|
|
UINT cb_idx, struct wined3d_buffer *buffer)
|
|
{
|
|
struct wined3d_cs_set_constant_buffer *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
|
|
op->type = type;
|
|
op->cb_idx = cb_idx;
|
|
op->buffer = buffer;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
|
|
const struct wined3d_cs_set_texture *op = data;
|
|
struct wined3d_texture *prev;
|
|
|
|
prev = cs->state.textures[op->stage];
|
|
cs->state.textures[op->stage] = op->texture;
|
|
|
|
if (op->texture)
|
|
{
|
|
if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
|
|
op->texture->sampler = op->stage;
|
|
|
|
if (!prev || op->texture->target != prev->target)
|
|
device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
|
|
|
|
if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
|
|
{
|
|
/* The source arguments for color and alpha ops have different
|
|
* meanings when a NULL texture is bound, so the COLOR_OP and
|
|
* ALPHA_OP have to be dirtified. */
|
|
device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
|
|
device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
|
|
}
|
|
}
|
|
|
|
if (prev)
|
|
{
|
|
if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Search for other stages the texture is bound to. Shouldn't
|
|
* happen if applications bind textures to a single stage only. */
|
|
TRACE("Searching for other stages the texture is bound to.\n");
|
|
for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
|
|
{
|
|
if (cs->state.textures[i] == prev)
|
|
{
|
|
TRACE("Texture is also bound to stage %u.\n", i);
|
|
prev->sampler = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
|
|
{
|
|
device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
|
|
device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
|
|
}
|
|
}
|
|
|
|
device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
|
|
{
|
|
struct wined3d_cs_set_texture *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_TEXTURE;
|
|
op->stage = stage;
|
|
op->texture = texture;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_sampler *op = data;
|
|
|
|
cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
|
|
}
|
|
|
|
void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
|
|
UINT sampler_idx, struct wined3d_sampler *sampler)
|
|
{
|
|
struct wined3d_cs_set_sampler *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_SAMPLER;
|
|
op->type = type;
|
|
op->sampler_idx = sampler_idx;
|
|
op->sampler = sampler;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_shader *op = data;
|
|
|
|
cs->state.shader[op->type] = op->shader;
|
|
device_invalidate_state(cs->device, STATE_SHADER(op->type));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
|
|
{
|
|
struct wined3d_cs_set_shader *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_SHADER;
|
|
op->type = type;
|
|
op->shader = shader;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_render_state *op = data;
|
|
|
|
cs->state.render_states[op->state] = op->value;
|
|
device_invalidate_state(cs->device, STATE_RENDER(op->state));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
|
|
{
|
|
struct wined3d_cs_set_render_state *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
|
|
op->state = state;
|
|
op->value = value;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_texture_state *op = data;
|
|
|
|
cs->state.texture_states[op->stage][op->state] = op->value;
|
|
device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
|
|
enum wined3d_texture_stage_state state, DWORD value)
|
|
{
|
|
struct wined3d_cs_set_texture_state *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
|
|
op->stage = stage;
|
|
op->state = state;
|
|
op->value = value;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_sampler_state *op = data;
|
|
|
|
cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
|
|
device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
|
|
enum wined3d_sampler_state state, DWORD value)
|
|
{
|
|
struct wined3d_cs_set_sampler_state *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
|
|
op->sampler_idx = sampler_idx;
|
|
op->state = state;
|
|
op->value = value;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_transform *op = data;
|
|
|
|
cs->state.transforms[op->state] = *op->matrix;
|
|
if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->gl_info.limits.blends))
|
|
device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
|
|
const struct wined3d_matrix *matrix)
|
|
{
|
|
struct wined3d_cs_set_transform *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
|
|
op->state = state;
|
|
op->matrix = matrix;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_clip_plane *op = data;
|
|
|
|
cs->state.clip_planes[op->plane_idx] = *op->plane;
|
|
device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
|
|
}
|
|
|
|
void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
|
|
{
|
|
struct wined3d_cs_set_clip_plane *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
|
|
op->plane_idx = plane_idx;
|
|
op->plane = plane;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
const struct wined3d_cs_set_material *op = data;
|
|
|
|
cs->state.material = *op->material;
|
|
device_invalidate_state(cs->device, STATE_MATERIAL);
|
|
}
|
|
|
|
void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
|
|
{
|
|
struct wined3d_cs_set_material *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_SET_MATERIAL;
|
|
op->material = material;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
|
|
{
|
|
struct wined3d_adapter *adapter = cs->device->adapter;
|
|
HRESULT hr;
|
|
|
|
state_cleanup(&cs->state);
|
|
memset(&cs->state, 0, sizeof(cs->state));
|
|
if (FAILED(hr = state_init(&cs->state, &cs->fb, &adapter->gl_info, &adapter->d3d_info,
|
|
WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT)))
|
|
ERR("Failed to initialize CS state, hr %#x.\n", hr);
|
|
}
|
|
|
|
void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
|
|
{
|
|
struct wined3d_cs_reset_state *op;
|
|
|
|
op = cs->ops->require_space(cs, sizeof(*op));
|
|
op->opcode = WINED3D_CS_OP_RESET_STATE;
|
|
|
|
cs->ops->submit(cs);
|
|
}
|
|
|
|
static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
|
|
{
|
|
/* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present,
|
|
/* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear,
|
|
/* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw,
|
|
/* WINED3D_CS_OP_SET_VIEWPORT */ wined3d_cs_exec_set_viewport,
|
|
/* WINED3D_CS_OP_SET_SCISSOR_RECT */ wined3d_cs_exec_set_scissor_rect,
|
|
/* WINED3D_CS_OP_SET_RENDER_TARGET */ wined3d_cs_exec_set_render_target,
|
|
/* WINED3D_CS_OP_SET_DEPTH_STENCIL */ wined3d_cs_exec_set_depth_stencil,
|
|
/* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration,
|
|
/* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source,
|
|
/* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ */ wined3d_cs_exec_set_stream_source_freq,
|
|
/* WINED3D_CS_OP_SET_STREAM_OUTPUT */ wined3d_cs_exec_set_stream_output,
|
|
/* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer,
|
|
/* WINED3D_CS_OP_SET_CONSTANT_BUFFER */ wined3d_cs_exec_set_constant_buffer,
|
|
/* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture,
|
|
/* WINED3D_CS_OP_SET_SAMPLER */ wined3d_cs_exec_set_sampler,
|
|
/* WINED3D_CS_OP_SET_SHADER */ wined3d_cs_exec_set_shader,
|
|
/* WINED3D_CS_OP_SET_RENDER_STATE */ wined3d_cs_exec_set_render_state,
|
|
/* WINED3D_CS_OP_SET_TEXTURE_STATE */ wined3d_cs_exec_set_texture_state,
|
|
/* WINED3D_CS_OP_SET_SAMPLER_STATE */ wined3d_cs_exec_set_sampler_state,
|
|
/* WINED3D_CS_OP_SET_TRANSFORM */ wined3d_cs_exec_set_transform,
|
|
/* WINED3D_CS_OP_SET_CLIP_PLANE */ wined3d_cs_exec_set_clip_plane,
|
|
/* WINED3D_CS_OP_SET_MATERIAL */ wined3d_cs_exec_set_material,
|
|
/* WINED3D_CS_OP_RESET_STATE */ wined3d_cs_exec_reset_state,
|
|
};
|
|
|
|
static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size)
|
|
{
|
|
if (size > cs->data_size)
|
|
{
|
|
void *new_data;
|
|
|
|
size = max( size, cs->data_size * 2 );
|
|
if (!(new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, size)))
|
|
return NULL;
|
|
|
|
cs->data_size = size;
|
|
cs->data = new_data;
|
|
}
|
|
|
|
return cs->data;
|
|
}
|
|
|
|
static void wined3d_cs_st_submit(struct wined3d_cs *cs)
|
|
{
|
|
enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)cs->data;
|
|
|
|
wined3d_cs_op_handlers[opcode](cs, cs->data);
|
|
}
|
|
|
|
static const struct wined3d_cs_ops wined3d_cs_st_ops =
|
|
{
|
|
wined3d_cs_st_require_space,
|
|
wined3d_cs_st_submit,
|
|
};
|
|
|
|
struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
|
|
{
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
struct wined3d_cs *cs;
|
|
|
|
if (!(cs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cs))))
|
|
return NULL;
|
|
|
|
if (!(cs->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(*cs->fb.render_targets) * gl_info->limits.buffers)))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, cs);
|
|
return NULL;
|
|
}
|
|
|
|
if (FAILED(state_init(&cs->state, &cs->fb, gl_info, &device->adapter->d3d_info,
|
|
WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT)))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
|
|
HeapFree(GetProcessHeap(), 0, cs);
|
|
return NULL;
|
|
}
|
|
|
|
cs->ops = &wined3d_cs_st_ops;
|
|
cs->device = device;
|
|
|
|
cs->data_size = WINED3D_INITIAL_CS_SIZE;
|
|
if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size)))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, cs);
|
|
return NULL;
|
|
}
|
|
|
|
return cs;
|
|
}
|
|
|
|
void wined3d_cs_destroy(struct wined3d_cs *cs)
|
|
{
|
|
state_cleanup(&cs->state);
|
|
HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
|
|
HeapFree(GetProcessHeap(), 0, cs->data);
|
|
HeapFree(GetProcessHeap(), 0, cs);
|
|
}
|