162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2015 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the
862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1262306a36Sopenharmony_ci * the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1662306a36Sopenharmony_ci * of the Software.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci **************************************************************************/
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * This file implements the vmwgfx context binding manager,
2962306a36Sopenharmony_ci * The sole reason for having to use this code is that vmware guest
3062306a36Sopenharmony_ci * backed contexts can be swapped out to their backing mobs by the device
3162306a36Sopenharmony_ci * at any time, also swapped in at any time. At swapin time, the device
3262306a36Sopenharmony_ci * validates the context bindings to make sure they point to valid resources.
3362306a36Sopenharmony_ci * It's this outside-of-drawcall validation (that can happen at any time),
3462306a36Sopenharmony_ci * that makes this code necessary.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * We therefore need to kill any context bindings pointing to a resource
3762306a36Sopenharmony_ci * when the resource is swapped out. Furthermore, if the vmwgfx driver has
3862306a36Sopenharmony_ci * swapped out the context we can't swap it in again to kill bindings because
3962306a36Sopenharmony_ci * of backing mob reservation lockdep violations, so as part of
4062306a36Sopenharmony_ci * context swapout, also kill all bindings of a context, so that they are
4162306a36Sopenharmony_ci * already killed if a resource to which a binding points
4262306a36Sopenharmony_ci * needs to be swapped out.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Note that a resource can be pointed to by bindings from multiple contexts,
4562306a36Sopenharmony_ci * Therefore we can't easily protect this data by a per context mutex
4662306a36Sopenharmony_ci * (unless we use deadlock-safe WW mutexes). So we use a global binding_mutex
4762306a36Sopenharmony_ci * to protect all binding manager data.
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Finally, any association between a context and a global resource
5062306a36Sopenharmony_ci * (surface, shader or even DX query) is conceptually a context binding that
5162306a36Sopenharmony_ci * needs to be tracked by this code.
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#include "vmwgfx_drv.h"
5562306a36Sopenharmony_ci#include "vmwgfx_binding.h"
5662306a36Sopenharmony_ci#include "device_include/svga3d_reg.h"
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define VMW_BINDING_RT_BIT     0
5962306a36Sopenharmony_ci#define VMW_BINDING_PS_BIT     1
6062306a36Sopenharmony_ci#define VMW_BINDING_SO_T_BIT   2
6162306a36Sopenharmony_ci#define VMW_BINDING_VB_BIT     3
6262306a36Sopenharmony_ci#define VMW_BINDING_UAV_BIT    4
6362306a36Sopenharmony_ci#define VMW_BINDING_CS_UAV_BIT 5
6462306a36Sopenharmony_ci#define VMW_BINDING_NUM_BITS   6
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define VMW_BINDING_PS_SR_BIT  0
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/**
6962306a36Sopenharmony_ci * struct vmw_ctx_binding_state - per context binding state
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * @dev_priv: Pointer to device private structure.
7262306a36Sopenharmony_ci * @list: linked list of individual active bindings.
7362306a36Sopenharmony_ci * @render_targets: Render target bindings.
7462306a36Sopenharmony_ci * @texture_units: Texture units bindings.
7562306a36Sopenharmony_ci * @ds_view: Depth-stencil view binding.
7662306a36Sopenharmony_ci * @so_targets: StreamOutput target bindings.
7762306a36Sopenharmony_ci * @vertex_buffers: Vertex buffer bindings.
7862306a36Sopenharmony_ci * @index_buffer: Index buffer binding.
7962306a36Sopenharmony_ci * @per_shader: Per shader-type bindings.
8062306a36Sopenharmony_ci * @ua_views: UAV bindings.
8162306a36Sopenharmony_ci * @so_state: StreamOutput bindings.
8262306a36Sopenharmony_ci * @dirty: Bitmap tracking per binding-type changes that have not yet
8362306a36Sopenharmony_ci * been emitted to the device.
8462306a36Sopenharmony_ci * @dirty_vb: Bitmap tracking individual vertex buffer binding changes that
8562306a36Sopenharmony_ci * have not yet been emitted to the device.
8662306a36Sopenharmony_ci * @bind_cmd_buffer: Scratch space used to construct binding commands.
8762306a36Sopenharmony_ci * @bind_cmd_count: Number of binding command data entries in @bind_cmd_buffer
8862306a36Sopenharmony_ci * @bind_first_slot: Used together with @bind_cmd_buffer to indicate the
8962306a36Sopenharmony_ci * device binding slot of the first command data entry in @bind_cmd_buffer.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * Note that this structure also provides storage space for the individual
9262306a36Sopenharmony_ci * struct vmw_ctx_binding objects, so that no dynamic allocation is needed
9362306a36Sopenharmony_ci * for individual bindings.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistruct vmw_ctx_binding_state {
9762306a36Sopenharmony_ci	struct vmw_private *dev_priv;
9862306a36Sopenharmony_ci	struct list_head list;
9962306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_view render_targets[SVGA3D_RT_MAX];
10062306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_tex texture_units[SVGA3D_NUM_TEXTURE_UNITS];
10162306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_view ds_view;
10262306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_so_target so_targets[SVGA3D_DX_MAX_SOTARGETS];
10362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_vb vertex_buffers[SVGA3D_DX_MAX_VERTEXBUFFERS];
10462306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_ib index_buffer;
10562306a36Sopenharmony_ci	struct vmw_dx_shader_bindings per_shader[SVGA3D_NUM_SHADERTYPE];
10662306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_uav ua_views[VMW_MAX_UAV_BIND_TYPE];
10762306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_so so_state;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	unsigned long dirty;
11062306a36Sopenharmony_ci	DECLARE_BITMAP(dirty_vb, SVGA3D_DX_MAX_VERTEXBUFFERS);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	u32 bind_cmd_buffer[VMW_MAX_VIEW_BINDINGS];
11362306a36Sopenharmony_ci	u32 bind_cmd_count;
11462306a36Sopenharmony_ci	u32 bind_first_slot;
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int vmw_binding_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);
11862306a36Sopenharmony_cistatic int vmw_binding_scrub_render_target(struct vmw_ctx_bindinfo *bi,
11962306a36Sopenharmony_ci					   bool rebind);
12062306a36Sopenharmony_cistatic int vmw_binding_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);
12162306a36Sopenharmony_cistatic int vmw_binding_scrub_cb(struct vmw_ctx_bindinfo *bi, bool rebind);
12262306a36Sopenharmony_cistatic int vmw_binding_scrub_dx_rt(struct vmw_ctx_bindinfo *bi, bool rebind);
12362306a36Sopenharmony_cistatic int vmw_binding_scrub_sr(struct vmw_ctx_bindinfo *bi, bool rebind);
12462306a36Sopenharmony_cistatic int vmw_binding_scrub_so_target(struct vmw_ctx_bindinfo *bi, bool rebind);
12562306a36Sopenharmony_cistatic int vmw_binding_emit_dirty(struct vmw_ctx_binding_state *cbs);
12662306a36Sopenharmony_cistatic int vmw_binding_scrub_dx_shader(struct vmw_ctx_bindinfo *bi,
12762306a36Sopenharmony_ci				       bool rebind);
12862306a36Sopenharmony_cistatic int vmw_binding_scrub_ib(struct vmw_ctx_bindinfo *bi, bool rebind);
12962306a36Sopenharmony_cistatic int vmw_binding_scrub_vb(struct vmw_ctx_bindinfo *bi, bool rebind);
13062306a36Sopenharmony_cistatic int vmw_binding_scrub_uav(struct vmw_ctx_bindinfo *bi, bool rebind);
13162306a36Sopenharmony_cistatic int vmw_binding_scrub_cs_uav(struct vmw_ctx_bindinfo *bi, bool rebind);
13262306a36Sopenharmony_cistatic int vmw_binding_scrub_so(struct vmw_ctx_bindinfo *bi, bool rebind);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void vmw_binding_build_asserts(void) __attribute__ ((unused));
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_citypedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/**
13962306a36Sopenharmony_ci * struct vmw_binding_info - Per binding type information for the binding
14062306a36Sopenharmony_ci * manager
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci * @size: The size of the struct binding derived from a struct vmw_ctx_bindinfo.
14362306a36Sopenharmony_ci * @offsets: array[shader_slot] of offsets to the array[slot]
14462306a36Sopenharmony_ci * of struct bindings for the binding type.
14562306a36Sopenharmony_ci * @scrub_func: Pointer to the scrub function for this binding type.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Holds static information to help optimize the binding manager and avoid
14862306a36Sopenharmony_ci * an excessive amount of switch statements.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistruct vmw_binding_info {
15162306a36Sopenharmony_ci	size_t size;
15262306a36Sopenharmony_ci	const size_t *offsets;
15362306a36Sopenharmony_ci	vmw_scrub_func scrub_func;
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * A number of static variables that help determine the scrub func and the
15862306a36Sopenharmony_ci * location of the struct vmw_ctx_bindinfo slots for each binding type.
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_cistatic const size_t vmw_binding_shader_offsets[] = {
16162306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[0].shader),
16262306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[1].shader),
16362306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[2].shader),
16462306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[3].shader),
16562306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[4].shader),
16662306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[5].shader),
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_cistatic const size_t vmw_binding_rt_offsets[] = {
16962306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, render_targets),
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_cistatic const size_t vmw_binding_tex_offsets[] = {
17262306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, texture_units),
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_cistatic const size_t vmw_binding_cb_offsets[] = {
17562306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[0].const_buffers),
17662306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[1].const_buffers),
17762306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[2].const_buffers),
17862306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[3].const_buffers),
17962306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[4].const_buffers),
18062306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[5].const_buffers),
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_cistatic const size_t vmw_binding_dx_ds_offsets[] = {
18362306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, ds_view),
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_cistatic const size_t vmw_binding_sr_offsets[] = {
18662306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[0].shader_res),
18762306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[1].shader_res),
18862306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[2].shader_res),
18962306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[3].shader_res),
19062306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[4].shader_res),
19162306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, per_shader[5].shader_res),
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_cistatic const size_t vmw_binding_so_target_offsets[] = {
19462306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, so_targets),
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_cistatic const size_t vmw_binding_vb_offsets[] = {
19762306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, vertex_buffers),
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_cistatic const size_t vmw_binding_ib_offsets[] = {
20062306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, index_buffer),
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_cistatic const size_t vmw_binding_uav_offsets[] = {
20362306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, ua_views[0].views),
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_cistatic const size_t vmw_binding_cs_uav_offsets[] = {
20662306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, ua_views[1].views),
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_cistatic const size_t vmw_binding_so_offsets[] = {
20962306a36Sopenharmony_ci	offsetof(struct vmw_ctx_binding_state, so_state),
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic const struct vmw_binding_info vmw_binding_infos[] = {
21362306a36Sopenharmony_ci	[vmw_ctx_binding_shader] = {
21462306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_shader),
21562306a36Sopenharmony_ci		.offsets = vmw_binding_shader_offsets,
21662306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_shader},
21762306a36Sopenharmony_ci	[vmw_ctx_binding_rt] = {
21862306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
21962306a36Sopenharmony_ci		.offsets = vmw_binding_rt_offsets,
22062306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_render_target},
22162306a36Sopenharmony_ci	[vmw_ctx_binding_tex] = {
22262306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_tex),
22362306a36Sopenharmony_ci		.offsets = vmw_binding_tex_offsets,
22462306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_texture},
22562306a36Sopenharmony_ci	[vmw_ctx_binding_cb] = {
22662306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_cb),
22762306a36Sopenharmony_ci		.offsets = vmw_binding_cb_offsets,
22862306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_cb},
22962306a36Sopenharmony_ci	[vmw_ctx_binding_dx_shader] = {
23062306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_shader),
23162306a36Sopenharmony_ci		.offsets = vmw_binding_shader_offsets,
23262306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_dx_shader},
23362306a36Sopenharmony_ci	[vmw_ctx_binding_dx_rt] = {
23462306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
23562306a36Sopenharmony_ci		.offsets = vmw_binding_rt_offsets,
23662306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_dx_rt},
23762306a36Sopenharmony_ci	[vmw_ctx_binding_sr] = {
23862306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
23962306a36Sopenharmony_ci		.offsets = vmw_binding_sr_offsets,
24062306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_sr},
24162306a36Sopenharmony_ci	[vmw_ctx_binding_ds] = {
24262306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
24362306a36Sopenharmony_ci		.offsets = vmw_binding_dx_ds_offsets,
24462306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_dx_rt},
24562306a36Sopenharmony_ci	[vmw_ctx_binding_so_target] = {
24662306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_so_target),
24762306a36Sopenharmony_ci		.offsets = vmw_binding_so_target_offsets,
24862306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_so_target},
24962306a36Sopenharmony_ci	[vmw_ctx_binding_vb] = {
25062306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_vb),
25162306a36Sopenharmony_ci		.offsets = vmw_binding_vb_offsets,
25262306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_vb},
25362306a36Sopenharmony_ci	[vmw_ctx_binding_ib] = {
25462306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_ib),
25562306a36Sopenharmony_ci		.offsets = vmw_binding_ib_offsets,
25662306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_ib},
25762306a36Sopenharmony_ci	[vmw_ctx_binding_uav] = {
25862306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
25962306a36Sopenharmony_ci		.offsets = vmw_binding_uav_offsets,
26062306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_uav},
26162306a36Sopenharmony_ci	[vmw_ctx_binding_cs_uav] = {
26262306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_view),
26362306a36Sopenharmony_ci		.offsets = vmw_binding_cs_uav_offsets,
26462306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_cs_uav},
26562306a36Sopenharmony_ci	[vmw_ctx_binding_so] = {
26662306a36Sopenharmony_ci		.size = sizeof(struct vmw_ctx_bindinfo_so),
26762306a36Sopenharmony_ci		.offsets = vmw_binding_so_offsets,
26862306a36Sopenharmony_ci		.scrub_func = vmw_binding_scrub_so},
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * vmw_cbs_context - Return a pointer to the context resource of a
27362306a36Sopenharmony_ci * context binding state tracker.
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * @cbs: The context binding state tracker.
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * Provided there are any active bindings, this function will return an
27862306a36Sopenharmony_ci * unreferenced pointer to the context resource that owns the context
27962306a36Sopenharmony_ci * binding state tracker. If there are no active bindings, this function
28062306a36Sopenharmony_ci * will return NULL. Note that the caller must somehow ensure that a reference
28162306a36Sopenharmony_ci * is held on the context resource prior to calling this function.
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cistatic const struct vmw_resource *
28462306a36Sopenharmony_civmw_cbs_context(const struct vmw_ctx_binding_state *cbs)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	if (list_empty(&cbs->list))
28762306a36Sopenharmony_ci		return NULL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return list_first_entry(&cbs->list, struct vmw_ctx_bindinfo,
29062306a36Sopenharmony_ci				ctx_list)->ctx;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * vmw_binding_loc - determine the struct vmw_ctx_bindinfo slot location.
29562306a36Sopenharmony_ci *
29662306a36Sopenharmony_ci * @cbs: Pointer to a struct vmw_ctx_binding state which holds the slot.
29762306a36Sopenharmony_ci * @bt: The binding type.
29862306a36Sopenharmony_ci * @shader_slot: The shader slot of the binding. If none, then set to 0.
29962306a36Sopenharmony_ci * @slot: The slot of the binding.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cistatic struct vmw_ctx_bindinfo *
30262306a36Sopenharmony_civmw_binding_loc(struct vmw_ctx_binding_state *cbs,
30362306a36Sopenharmony_ci		enum vmw_ctx_binding_type bt, u32 shader_slot, u32 slot)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	const struct vmw_binding_info *b = &vmw_binding_infos[bt];
30662306a36Sopenharmony_ci	size_t offset = b->offsets[shader_slot] + b->size*slot;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return (struct vmw_ctx_bindinfo *)((u8 *) cbs + offset);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/**
31262306a36Sopenharmony_ci * vmw_binding_drop: Stop tracking a context binding
31362306a36Sopenharmony_ci *
31462306a36Sopenharmony_ci * @bi: Pointer to binding tracker storage.
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Stops tracking a context binding, and re-initializes its storage.
31762306a36Sopenharmony_ci * Typically used when the context binding is replaced with a binding to
31862306a36Sopenharmony_ci * another (or the same, for that matter) resource.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_cistatic void vmw_binding_drop(struct vmw_ctx_bindinfo *bi)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	list_del(&bi->ctx_list);
32362306a36Sopenharmony_ci	if (!list_empty(&bi->res_list))
32462306a36Sopenharmony_ci		list_del(&bi->res_list);
32562306a36Sopenharmony_ci	bi->ctx = NULL;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/**
32962306a36Sopenharmony_ci * vmw_binding_add: Start tracking a context binding
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
33262306a36Sopenharmony_ci * @bi: Information about the binding to track.
33362306a36Sopenharmony_ci * @shader_slot: The shader slot of the binding.
33462306a36Sopenharmony_ci * @slot: The slot of the binding.
33562306a36Sopenharmony_ci *
33662306a36Sopenharmony_ci * Starts tracking the binding in the context binding
33762306a36Sopenharmony_ci * state structure @cbs.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_civoid vmw_binding_add(struct vmw_ctx_binding_state *cbs,
34062306a36Sopenharmony_ci		    const struct vmw_ctx_bindinfo *bi,
34162306a36Sopenharmony_ci		    u32 shader_slot, u32 slot)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *loc =
34462306a36Sopenharmony_ci		vmw_binding_loc(cbs, bi->bt, shader_slot, slot);
34562306a36Sopenharmony_ci	const struct vmw_binding_info *b = &vmw_binding_infos[bi->bt];
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (loc->ctx != NULL)
34862306a36Sopenharmony_ci		vmw_binding_drop(loc);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	memcpy(loc, bi, b->size);
35162306a36Sopenharmony_ci	loc->scrubbed = false;
35262306a36Sopenharmony_ci	list_add(&loc->ctx_list, &cbs->list);
35362306a36Sopenharmony_ci	INIT_LIST_HEAD(&loc->res_list);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * vmw_binding_cb_offset_update: Update the offset of a cb binding
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
36062306a36Sopenharmony_ci * @shader_slot: The shader slot of the binding.
36162306a36Sopenharmony_ci * @slot: The slot of the binding.
36262306a36Sopenharmony_ci * @offsetInBytes: The new offset of the binding.
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * Updates the offset of an existing cb binding in the context binding
36562306a36Sopenharmony_ci * state structure @cbs.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_civoid vmw_binding_cb_offset_update(struct vmw_ctx_binding_state *cbs,
36862306a36Sopenharmony_ci				  u32 shader_slot, u32 slot, u32 offsetInBytes)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *loc =
37162306a36Sopenharmony_ci		vmw_binding_loc(cbs, vmw_ctx_binding_cb, shader_slot, slot);
37262306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_cb *loc_cb =
37362306a36Sopenharmony_ci		(struct vmw_ctx_bindinfo_cb *)((u8 *) loc);
37462306a36Sopenharmony_ci	loc_cb->offset = offsetInBytes;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/**
37862306a36Sopenharmony_ci * vmw_binding_add_uav_index - Add UAV index for tracking.
37962306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
38062306a36Sopenharmony_ci * @slot: UAV type to which bind this index.
38162306a36Sopenharmony_ci * @index: The splice index to track.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_civoid vmw_binding_add_uav_index(struct vmw_ctx_binding_state *cbs, uint32 slot,
38462306a36Sopenharmony_ci			       uint32 index)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	cbs->ua_views[slot].index = index;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/**
39062306a36Sopenharmony_ci * vmw_binding_transfer: Transfer a context binding tracking entry.
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * @cbs: Pointer to the persistent context binding state tracker.
39362306a36Sopenharmony_ci * @from: Staged binding info built during execbuf
39462306a36Sopenharmony_ci * @bi: Information about the binding to track.
39562306a36Sopenharmony_ci *
39662306a36Sopenharmony_ci */
39762306a36Sopenharmony_cistatic void vmw_binding_transfer(struct vmw_ctx_binding_state *cbs,
39862306a36Sopenharmony_ci				 const struct vmw_ctx_binding_state *from,
39962306a36Sopenharmony_ci				 const struct vmw_ctx_bindinfo *bi)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	size_t offset = (unsigned long)bi - (unsigned long)from;
40262306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *loc = (struct vmw_ctx_bindinfo *)
40362306a36Sopenharmony_ci		((unsigned long) cbs + offset);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (loc->ctx != NULL) {
40662306a36Sopenharmony_ci		WARN_ON(bi->scrubbed);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		vmw_binding_drop(loc);
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (bi->res != NULL) {
41262306a36Sopenharmony_ci		memcpy(loc, bi, vmw_binding_infos[bi->bt].size);
41362306a36Sopenharmony_ci		list_add_tail(&loc->ctx_list, &cbs->list);
41462306a36Sopenharmony_ci		list_add_tail(&loc->res_list, &loc->res->binding_head);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci/**
41962306a36Sopenharmony_ci * vmw_binding_state_kill - Kill all bindings associated with a
42062306a36Sopenharmony_ci * struct vmw_ctx_binding state structure, and re-initialize the structure.
42162306a36Sopenharmony_ci *
42262306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci * Emits commands to scrub all bindings associated with the
42562306a36Sopenharmony_ci * context binding state tracker. Then re-initializes the whole structure.
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_civoid vmw_binding_state_kill(struct vmw_ctx_binding_state *cbs)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry, *next;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	vmw_binding_state_scrub(cbs);
43262306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
43362306a36Sopenharmony_ci		vmw_binding_drop(entry);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * vmw_binding_state_scrub - Scrub all bindings associated with a
43862306a36Sopenharmony_ci * struct vmw_ctx_binding state structure.
43962306a36Sopenharmony_ci *
44062306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * Emits commands to scrub all bindings associated with the
44362306a36Sopenharmony_ci * context binding state tracker.
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_civoid vmw_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	list_for_each_entry(entry, &cbs->list, ctx_list) {
45062306a36Sopenharmony_ci		if (!entry->scrubbed) {
45162306a36Sopenharmony_ci			(void) vmw_binding_infos[entry->bt].scrub_func
45262306a36Sopenharmony_ci				(entry, false);
45362306a36Sopenharmony_ci			entry->scrubbed = true;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	(void) vmw_binding_emit_dirty(cbs);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci/**
46162306a36Sopenharmony_ci * vmw_binding_res_list_kill - Kill all bindings on a
46262306a36Sopenharmony_ci * resource binding list
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci * @head: list head of resource binding list
46562306a36Sopenharmony_ci *
46662306a36Sopenharmony_ci * Kills all bindings associated with a specific resource. Typically
46762306a36Sopenharmony_ci * called before the resource is destroyed.
46862306a36Sopenharmony_ci */
46962306a36Sopenharmony_civoid vmw_binding_res_list_kill(struct list_head *head)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry, *next;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	vmw_binding_res_list_scrub(head);
47462306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, head, res_list)
47562306a36Sopenharmony_ci		vmw_binding_drop(entry);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * vmw_binding_res_list_scrub - Scrub all bindings on a
48062306a36Sopenharmony_ci * resource binding list
48162306a36Sopenharmony_ci *
48262306a36Sopenharmony_ci * @head: list head of resource binding list
48362306a36Sopenharmony_ci *
48462306a36Sopenharmony_ci * Scrub all bindings associated with a specific resource. Typically
48562306a36Sopenharmony_ci * called before the resource is evicted.
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_civoid vmw_binding_res_list_scrub(struct list_head *head)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	list_for_each_entry(entry, head, res_list) {
49262306a36Sopenharmony_ci		if (!entry->scrubbed) {
49362306a36Sopenharmony_ci			(void) vmw_binding_infos[entry->bt].scrub_func
49462306a36Sopenharmony_ci				(entry, false);
49562306a36Sopenharmony_ci			entry->scrubbed = true;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	list_for_each_entry(entry, head, res_list) {
50062306a36Sopenharmony_ci		struct vmw_ctx_binding_state *cbs =
50162306a36Sopenharmony_ci			vmw_context_binding_state(entry->ctx);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		(void) vmw_binding_emit_dirty(cbs);
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/**
50962306a36Sopenharmony_ci * vmw_binding_state_commit - Commit staged binding info
51062306a36Sopenharmony_ci *
51162306a36Sopenharmony_ci * @to:   Staged binding info area to copy into to.
51262306a36Sopenharmony_ci * @from: Staged binding info built during execbuf.
51362306a36Sopenharmony_ci *
51462306a36Sopenharmony_ci * Transfers binding info from a temporary structure
51562306a36Sopenharmony_ci * (typically used by execbuf) to the persistent
51662306a36Sopenharmony_ci * structure in the context. This can be done once commands have been
51762306a36Sopenharmony_ci * submitted to hardware
51862306a36Sopenharmony_ci */
51962306a36Sopenharmony_civoid vmw_binding_state_commit(struct vmw_ctx_binding_state *to,
52062306a36Sopenharmony_ci			      struct vmw_ctx_binding_state *from)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry, *next;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, &from->list, ctx_list) {
52562306a36Sopenharmony_ci		vmw_binding_transfer(to, from, entry);
52662306a36Sopenharmony_ci		vmw_binding_drop(entry);
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* Also transfer uav splice indices */
53062306a36Sopenharmony_ci	to->ua_views[0].index = from->ua_views[0].index;
53162306a36Sopenharmony_ci	to->ua_views[1].index = from->ua_views[1].index;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/**
53562306a36Sopenharmony_ci * vmw_binding_rebind_all - Rebind all scrubbed bindings of a context
53662306a36Sopenharmony_ci *
53762306a36Sopenharmony_ci * @cbs: Pointer to the context binding state tracker.
53862306a36Sopenharmony_ci *
53962306a36Sopenharmony_ci * Walks through the context binding list and rebinds all scrubbed
54062306a36Sopenharmony_ci * resources.
54162306a36Sopenharmony_ci */
54262306a36Sopenharmony_ciint vmw_binding_rebind_all(struct vmw_ctx_binding_state *cbs)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry;
54562306a36Sopenharmony_ci	int ret;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	list_for_each_entry(entry, &cbs->list, ctx_list) {
54862306a36Sopenharmony_ci		if (likely(!entry->scrubbed))
54962306a36Sopenharmony_ci			continue;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		if ((entry->res == NULL || entry->res->id ==
55262306a36Sopenharmony_ci			    SVGA3D_INVALID_ID))
55362306a36Sopenharmony_ci			continue;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		ret = vmw_binding_infos[entry->bt].scrub_func(entry, true);
55662306a36Sopenharmony_ci		if (unlikely(ret != 0))
55762306a36Sopenharmony_ci			return ret;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		entry->scrubbed = false;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return vmw_binding_emit_dirty(cbs);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/**
56662306a36Sopenharmony_ci * vmw_binding_scrub_shader - scrub a shader binding from a context.
56762306a36Sopenharmony_ci *
56862306a36Sopenharmony_ci * @bi: single binding information.
56962306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
57062306a36Sopenharmony_ci */
57162306a36Sopenharmony_cistatic int vmw_binding_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_shader *binding =
57462306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
57562306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
57662306a36Sopenharmony_ci	struct {
57762306a36Sopenharmony_ci		SVGA3dCmdHeader header;
57862306a36Sopenharmony_ci		SVGA3dCmdSetShader body;
57962306a36Sopenharmony_ci	} *cmd;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
58262306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
58362306a36Sopenharmony_ci		return -ENOMEM;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_SET_SHADER;
58662306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
58762306a36Sopenharmony_ci	cmd->body.cid = bi->ctx->id;
58862306a36Sopenharmony_ci	cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
58962306a36Sopenharmony_ci	cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
59062306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return 0;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci/**
59662306a36Sopenharmony_ci * vmw_binding_scrub_render_target - scrub a render target binding
59762306a36Sopenharmony_ci * from a context.
59862306a36Sopenharmony_ci *
59962306a36Sopenharmony_ci * @bi: single binding information.
60062306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
60162306a36Sopenharmony_ci */
60262306a36Sopenharmony_cistatic int vmw_binding_scrub_render_target(struct vmw_ctx_bindinfo *bi,
60362306a36Sopenharmony_ci					   bool rebind)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_view *binding =
60662306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
60762306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
60862306a36Sopenharmony_ci	struct {
60962306a36Sopenharmony_ci		SVGA3dCmdHeader header;
61062306a36Sopenharmony_ci		SVGA3dCmdSetRenderTarget body;
61162306a36Sopenharmony_ci	} *cmd;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
61462306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
61562306a36Sopenharmony_ci		return -ENOMEM;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
61862306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
61962306a36Sopenharmony_ci	cmd->body.cid = bi->ctx->id;
62062306a36Sopenharmony_ci	cmd->body.type = binding->slot;
62162306a36Sopenharmony_ci	cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
62262306a36Sopenharmony_ci	cmd->body.target.face = 0;
62362306a36Sopenharmony_ci	cmd->body.target.mipmap = 0;
62462306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	return 0;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci/**
63062306a36Sopenharmony_ci * vmw_binding_scrub_texture - scrub a texture binding from a context.
63162306a36Sopenharmony_ci *
63262306a36Sopenharmony_ci * @bi: single binding information.
63362306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci * TODO: Possibly complement this function with a function that takes
63662306a36Sopenharmony_ci * a list of texture bindings and combines them to a single command.
63762306a36Sopenharmony_ci */
63862306a36Sopenharmony_cistatic int vmw_binding_scrub_texture(struct vmw_ctx_bindinfo *bi,
63962306a36Sopenharmony_ci				     bool rebind)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_tex *binding =
64262306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
64362306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
64462306a36Sopenharmony_ci	struct {
64562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
64662306a36Sopenharmony_ci		struct {
64762306a36Sopenharmony_ci			SVGA3dCmdSetTextureState c;
64862306a36Sopenharmony_ci			SVGA3dTextureState s1;
64962306a36Sopenharmony_ci		} body;
65062306a36Sopenharmony_ci	} *cmd;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
65362306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
65462306a36Sopenharmony_ci		return -ENOMEM;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
65762306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
65862306a36Sopenharmony_ci	cmd->body.c.cid = bi->ctx->id;
65962306a36Sopenharmony_ci	cmd->body.s1.stage = binding->texture_stage;
66062306a36Sopenharmony_ci	cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
66162306a36Sopenharmony_ci	cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
66262306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/**
66862306a36Sopenharmony_ci * vmw_binding_scrub_dx_shader - scrub a dx shader binding from a context.
66962306a36Sopenharmony_ci *
67062306a36Sopenharmony_ci * @bi: single binding information.
67162306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
67262306a36Sopenharmony_ci */
67362306a36Sopenharmony_cistatic int vmw_binding_scrub_dx_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_shader *binding =
67662306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
67762306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
67862306a36Sopenharmony_ci	struct {
67962306a36Sopenharmony_ci		SVGA3dCmdHeader header;
68062306a36Sopenharmony_ci		SVGA3dCmdDXSetShader body;
68162306a36Sopenharmony_ci	} *cmd;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), bi->ctx->id);
68462306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
68562306a36Sopenharmony_ci		return -ENOMEM;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_SHADER;
68862306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
68962306a36Sopenharmony_ci	cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
69062306a36Sopenharmony_ci	cmd->body.shaderId = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
69162306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/**
69762306a36Sopenharmony_ci * vmw_binding_scrub_cb - scrub a constant buffer binding from a context.
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci * @bi: single binding information.
70062306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
70162306a36Sopenharmony_ci */
70262306a36Sopenharmony_cistatic int vmw_binding_scrub_cb(struct vmw_ctx_bindinfo *bi, bool rebind)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_cb *binding =
70562306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
70662306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
70762306a36Sopenharmony_ci	struct {
70862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
70962306a36Sopenharmony_ci		SVGA3dCmdDXSetSingleConstantBuffer body;
71062306a36Sopenharmony_ci	} *cmd;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), bi->ctx->id);
71362306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
71462306a36Sopenharmony_ci		return -ENOMEM;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER;
71762306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
71862306a36Sopenharmony_ci	cmd->body.slot = binding->slot;
71962306a36Sopenharmony_ci	cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
72062306a36Sopenharmony_ci	if (rebind) {
72162306a36Sopenharmony_ci		cmd->body.offsetInBytes = binding->offset;
72262306a36Sopenharmony_ci		cmd->body.sizeInBytes = binding->size;
72362306a36Sopenharmony_ci		cmd->body.sid = bi->res->id;
72462306a36Sopenharmony_ci	} else {
72562306a36Sopenharmony_ci		cmd->body.offsetInBytes = 0;
72662306a36Sopenharmony_ci		cmd->body.sizeInBytes = 0;
72762306a36Sopenharmony_ci		cmd->body.sid = SVGA3D_INVALID_ID;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return 0;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci/**
73562306a36Sopenharmony_ci * vmw_collect_view_ids - Build view id data for a view binding command
73662306a36Sopenharmony_ci * without checking which bindings actually need to be emitted
73762306a36Sopenharmony_ci *
73862306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
73962306a36Sopenharmony_ci * @biv: Pointer to where the binding info array is stored in @cbs
74062306a36Sopenharmony_ci * @max_num: Maximum number of entries in the @bi array.
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * Scans the @bi array for bindings and builds a buffer of view id data.
74362306a36Sopenharmony_ci * Stops at the first non-existing binding in the @bi array.
74462306a36Sopenharmony_ci * On output, @cbs->bind_cmd_count contains the number of bindings to be
74562306a36Sopenharmony_ci * emitted, @cbs->bind_first_slot is set to zero, and @cbs->bind_cmd_buffer
74662306a36Sopenharmony_ci * contains the command data.
74762306a36Sopenharmony_ci */
74862306a36Sopenharmony_cistatic void vmw_collect_view_ids(struct vmw_ctx_binding_state *cbs,
74962306a36Sopenharmony_ci				 const struct vmw_ctx_bindinfo_view *biv,
75062306a36Sopenharmony_ci				 u32 max_num)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	unsigned long i;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	cbs->bind_cmd_count = 0;
75562306a36Sopenharmony_ci	cbs->bind_first_slot = 0;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	for (i = 0; i < max_num; ++i, ++biv) {
75862306a36Sopenharmony_ci		if (!biv->bi.ctx)
75962306a36Sopenharmony_ci			break;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		cbs->bind_cmd_buffer[cbs->bind_cmd_count++] =
76262306a36Sopenharmony_ci			((biv->bi.scrubbed) ?
76362306a36Sopenharmony_ci			 SVGA3D_INVALID_ID : biv->bi.res->id);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/**
76862306a36Sopenharmony_ci * vmw_collect_dirty_view_ids - Build view id data for a view binding command
76962306a36Sopenharmony_ci *
77062306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
77162306a36Sopenharmony_ci * @bi: Pointer to where the binding info array is stored in @cbs
77262306a36Sopenharmony_ci * @dirty: Bitmap indicating which bindings need to be emitted.
77362306a36Sopenharmony_ci * @max_num: Maximum number of entries in the @bi array.
77462306a36Sopenharmony_ci *
77562306a36Sopenharmony_ci * Scans the @bi array for bindings that need to be emitted and
77662306a36Sopenharmony_ci * builds a buffer of view id data.
77762306a36Sopenharmony_ci * On output, @cbs->bind_cmd_count contains the number of bindings to be
77862306a36Sopenharmony_ci * emitted, @cbs->bind_first_slot indicates the index of the first emitted
77962306a36Sopenharmony_ci * binding, and @cbs->bind_cmd_buffer contains the command data.
78062306a36Sopenharmony_ci */
78162306a36Sopenharmony_cistatic void vmw_collect_dirty_view_ids(struct vmw_ctx_binding_state *cbs,
78262306a36Sopenharmony_ci				       const struct vmw_ctx_bindinfo *bi,
78362306a36Sopenharmony_ci				       unsigned long *dirty,
78462306a36Sopenharmony_ci				       u32 max_num)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_view *biv =
78762306a36Sopenharmony_ci		container_of(bi, struct vmw_ctx_bindinfo_view, bi);
78862306a36Sopenharmony_ci	unsigned long i, next_bit;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	cbs->bind_cmd_count = 0;
79162306a36Sopenharmony_ci	i = find_first_bit(dirty, max_num);
79262306a36Sopenharmony_ci	next_bit = i;
79362306a36Sopenharmony_ci	cbs->bind_first_slot = i;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	biv += i;
79662306a36Sopenharmony_ci	for (; i < max_num; ++i, ++biv) {
79762306a36Sopenharmony_ci		cbs->bind_cmd_buffer[cbs->bind_cmd_count++] =
79862306a36Sopenharmony_ci			((!biv->bi.ctx || biv->bi.scrubbed) ?
79962306a36Sopenharmony_ci			 SVGA3D_INVALID_ID : biv->bi.res->id);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		if (next_bit == i) {
80262306a36Sopenharmony_ci			next_bit = find_next_bit(dirty, max_num, i + 1);
80362306a36Sopenharmony_ci			if (next_bit >= max_num)
80462306a36Sopenharmony_ci				break;
80562306a36Sopenharmony_ci		}
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/**
81062306a36Sopenharmony_ci * vmw_emit_set_sr - Issue delayed DX shader resource binding commands
81162306a36Sopenharmony_ci *
81262306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
81362306a36Sopenharmony_ci * @shader_slot: The shader slot of the binding.
81462306a36Sopenharmony_ci */
81562306a36Sopenharmony_cistatic int vmw_emit_set_sr(struct vmw_ctx_binding_state *cbs,
81662306a36Sopenharmony_ci			   int shader_slot)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo *loc =
81962306a36Sopenharmony_ci		&cbs->per_shader[shader_slot].shader_res[0].bi;
82062306a36Sopenharmony_ci	struct {
82162306a36Sopenharmony_ci		SVGA3dCmdHeader header;
82262306a36Sopenharmony_ci		SVGA3dCmdDXSetShaderResources body;
82362306a36Sopenharmony_ci	} *cmd;
82462306a36Sopenharmony_ci	size_t cmd_size, view_id_size;
82562306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	vmw_collect_dirty_view_ids(cbs, loc,
82862306a36Sopenharmony_ci				   cbs->per_shader[shader_slot].dirty_sr,
82962306a36Sopenharmony_ci				   SVGA3D_DX_MAX_SRVIEWS);
83062306a36Sopenharmony_ci	if (cbs->bind_cmd_count == 0)
83162306a36Sopenharmony_ci		return 0;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	view_id_size = cbs->bind_cmd_count*sizeof(uint32);
83462306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + view_id_size;
83562306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
83662306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
83762306a36Sopenharmony_ci		return -ENOMEM;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_SHADER_RESOURCES;
84062306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + view_id_size;
84162306a36Sopenharmony_ci	cmd->body.type = shader_slot + SVGA3D_SHADERTYPE_MIN;
84262306a36Sopenharmony_ci	cmd->body.startView = cbs->bind_first_slot;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
84762306a36Sopenharmony_ci	bitmap_clear(cbs->per_shader[shader_slot].dirty_sr,
84862306a36Sopenharmony_ci		     cbs->bind_first_slot, cbs->bind_cmd_count);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	return 0;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci/**
85462306a36Sopenharmony_ci * vmw_emit_set_rt - Issue delayed DX rendertarget binding commands
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
85762306a36Sopenharmony_ci */
85862306a36Sopenharmony_cistatic int vmw_emit_set_rt(struct vmw_ctx_binding_state *cbs)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_view *loc = &cbs->render_targets[0];
86162306a36Sopenharmony_ci	struct {
86262306a36Sopenharmony_ci		SVGA3dCmdHeader header;
86362306a36Sopenharmony_ci		SVGA3dCmdDXSetRenderTargets body;
86462306a36Sopenharmony_ci	} *cmd;
86562306a36Sopenharmony_ci	size_t cmd_size, view_id_size;
86662306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	vmw_collect_view_ids(cbs, loc, SVGA3D_DX_MAX_RENDER_TARGETS);
86962306a36Sopenharmony_ci	view_id_size = cbs->bind_cmd_count*sizeof(uint32);
87062306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + view_id_size;
87162306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
87262306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
87362306a36Sopenharmony_ci		return -ENOMEM;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_RENDERTARGETS;
87662306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + view_id_size;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (cbs->ds_view.bi.ctx && !cbs->ds_view.bi.scrubbed)
87962306a36Sopenharmony_ci		cmd->body.depthStencilViewId = cbs->ds_view.bi.res->id;
88062306a36Sopenharmony_ci	else
88162306a36Sopenharmony_ci		cmd->body.depthStencilViewId = SVGA3D_INVALID_ID;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	return 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci/**
89262306a36Sopenharmony_ci * vmw_collect_so_targets - Build SVGA3dSoTarget data for a binding command
89362306a36Sopenharmony_ci * without checking which bindings actually need to be emitted
89462306a36Sopenharmony_ci *
89562306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
89662306a36Sopenharmony_ci * @biso: Pointer to where the binding info array is stored in @cbs
89762306a36Sopenharmony_ci * @max_num: Maximum number of entries in the @bi array.
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * Scans the @bi array for bindings and builds a buffer of SVGA3dSoTarget data.
90062306a36Sopenharmony_ci * Stops at the first non-existing binding in the @bi array.
90162306a36Sopenharmony_ci * On output, @cbs->bind_cmd_count contains the number of bindings to be
90262306a36Sopenharmony_ci * emitted, @cbs->bind_first_slot is set to zero, and @cbs->bind_cmd_buffer
90362306a36Sopenharmony_ci * contains the command data.
90462306a36Sopenharmony_ci */
90562306a36Sopenharmony_cistatic void vmw_collect_so_targets(struct vmw_ctx_binding_state *cbs,
90662306a36Sopenharmony_ci				   const struct vmw_ctx_bindinfo_so_target *biso,
90762306a36Sopenharmony_ci				   u32 max_num)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	unsigned long i;
91062306a36Sopenharmony_ci	SVGA3dSoTarget *so_buffer = (SVGA3dSoTarget *) cbs->bind_cmd_buffer;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	cbs->bind_cmd_count = 0;
91362306a36Sopenharmony_ci	cbs->bind_first_slot = 0;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	for (i = 0; i < max_num; ++i, ++biso, ++so_buffer,
91662306a36Sopenharmony_ci		    ++cbs->bind_cmd_count) {
91762306a36Sopenharmony_ci		if (!biso->bi.ctx)
91862306a36Sopenharmony_ci			break;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		if (!biso->bi.scrubbed) {
92162306a36Sopenharmony_ci			so_buffer->sid = biso->bi.res->id;
92262306a36Sopenharmony_ci			so_buffer->offset = biso->offset;
92362306a36Sopenharmony_ci			so_buffer->sizeInBytes = biso->size;
92462306a36Sopenharmony_ci		} else {
92562306a36Sopenharmony_ci			so_buffer->sid = SVGA3D_INVALID_ID;
92662306a36Sopenharmony_ci			so_buffer->offset = 0;
92762306a36Sopenharmony_ci			so_buffer->sizeInBytes = 0;
92862306a36Sopenharmony_ci		}
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/**
93362306a36Sopenharmony_ci * vmw_emit_set_so_target - Issue delayed streamout binding commands
93462306a36Sopenharmony_ci *
93562306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
93662306a36Sopenharmony_ci */
93762306a36Sopenharmony_cistatic int vmw_emit_set_so_target(struct vmw_ctx_binding_state *cbs)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_so_target *loc = &cbs->so_targets[0];
94062306a36Sopenharmony_ci	struct {
94162306a36Sopenharmony_ci		SVGA3dCmdHeader header;
94262306a36Sopenharmony_ci		SVGA3dCmdDXSetSOTargets body;
94362306a36Sopenharmony_ci	} *cmd;
94462306a36Sopenharmony_ci	size_t cmd_size, so_target_size;
94562306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	vmw_collect_so_targets(cbs, loc, SVGA3D_DX_MAX_SOTARGETS);
94862306a36Sopenharmony_ci	if (cbs->bind_cmd_count == 0)
94962306a36Sopenharmony_ci		return 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	so_target_size = cbs->bind_cmd_count*sizeof(SVGA3dSoTarget);
95262306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + so_target_size;
95362306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
95462306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
95562306a36Sopenharmony_ci		return -ENOMEM;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_SOTARGETS;
95862306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + so_target_size;
95962306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, so_target_size);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci/**
96862306a36Sopenharmony_ci * vmw_binding_emit_dirty_ps - Issue delayed per shader binding commands
96962306a36Sopenharmony_ci *
97062306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
97162306a36Sopenharmony_ci *
97262306a36Sopenharmony_ci */
97362306a36Sopenharmony_cistatic int vmw_binding_emit_dirty_ps(struct vmw_ctx_binding_state *cbs)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct vmw_dx_shader_bindings *sb = &cbs->per_shader[0];
97662306a36Sopenharmony_ci	u32 i;
97762306a36Sopenharmony_ci	int ret;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	for (i = 0; i < SVGA3D_NUM_SHADERTYPE_DX10; ++i, ++sb) {
98062306a36Sopenharmony_ci		if (!test_bit(VMW_BINDING_PS_SR_BIT, &sb->dirty))
98162306a36Sopenharmony_ci			continue;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		ret = vmw_emit_set_sr(cbs, i);
98462306a36Sopenharmony_ci		if (ret)
98562306a36Sopenharmony_ci			break;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		__clear_bit(VMW_BINDING_PS_SR_BIT, &sb->dirty);
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	return 0;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/**
99462306a36Sopenharmony_ci * vmw_collect_dirty_vbs - Build SVGA3dVertexBuffer data for a
99562306a36Sopenharmony_ci * SVGA3dCmdDXSetVertexBuffers command
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
99862306a36Sopenharmony_ci * @bi: Pointer to where the binding info array is stored in @cbs
99962306a36Sopenharmony_ci * @dirty: Bitmap indicating which bindings need to be emitted.
100062306a36Sopenharmony_ci * @max_num: Maximum number of entries in the @bi array.
100162306a36Sopenharmony_ci *
100262306a36Sopenharmony_ci * Scans the @bi array for bindings that need to be emitted and
100362306a36Sopenharmony_ci * builds a buffer of SVGA3dVertexBuffer data.
100462306a36Sopenharmony_ci * On output, @cbs->bind_cmd_count contains the number of bindings to be
100562306a36Sopenharmony_ci * emitted, @cbs->bind_first_slot indicates the index of the first emitted
100662306a36Sopenharmony_ci * binding, and @cbs->bind_cmd_buffer contains the command data.
100762306a36Sopenharmony_ci */
100862306a36Sopenharmony_cistatic void vmw_collect_dirty_vbs(struct vmw_ctx_binding_state *cbs,
100962306a36Sopenharmony_ci				  const struct vmw_ctx_bindinfo *bi,
101062306a36Sopenharmony_ci				  unsigned long *dirty,
101162306a36Sopenharmony_ci				  u32 max_num)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_vb *biv =
101462306a36Sopenharmony_ci		container_of(bi, struct vmw_ctx_bindinfo_vb, bi);
101562306a36Sopenharmony_ci	unsigned long i, next_bit;
101662306a36Sopenharmony_ci	SVGA3dVertexBuffer *vbs = (SVGA3dVertexBuffer *) &cbs->bind_cmd_buffer;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	cbs->bind_cmd_count = 0;
101962306a36Sopenharmony_ci	i = find_first_bit(dirty, max_num);
102062306a36Sopenharmony_ci	next_bit = i;
102162306a36Sopenharmony_ci	cbs->bind_first_slot = i;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	biv += i;
102462306a36Sopenharmony_ci	for (; i < max_num; ++i, ++biv, ++vbs) {
102562306a36Sopenharmony_ci		if (!biv->bi.ctx || biv->bi.scrubbed) {
102662306a36Sopenharmony_ci			vbs->sid = SVGA3D_INVALID_ID;
102762306a36Sopenharmony_ci			vbs->stride = 0;
102862306a36Sopenharmony_ci			vbs->offset = 0;
102962306a36Sopenharmony_ci		} else {
103062306a36Sopenharmony_ci			vbs->sid = biv->bi.res->id;
103162306a36Sopenharmony_ci			vbs->stride = biv->stride;
103262306a36Sopenharmony_ci			vbs->offset = biv->offset;
103362306a36Sopenharmony_ci		}
103462306a36Sopenharmony_ci		cbs->bind_cmd_count++;
103562306a36Sopenharmony_ci		if (next_bit == i) {
103662306a36Sopenharmony_ci			next_bit = find_next_bit(dirty, max_num, i + 1);
103762306a36Sopenharmony_ci			if (next_bit >= max_num)
103862306a36Sopenharmony_ci				break;
103962306a36Sopenharmony_ci		}
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci/**
104462306a36Sopenharmony_ci * vmw_emit_set_vb - Issue delayed vertex buffer binding commands
104562306a36Sopenharmony_ci *
104662306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
104762306a36Sopenharmony_ci *
104862306a36Sopenharmony_ci */
104962306a36Sopenharmony_cistatic int vmw_emit_set_vb(struct vmw_ctx_binding_state *cbs)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo *loc =
105262306a36Sopenharmony_ci		&cbs->vertex_buffers[0].bi;
105362306a36Sopenharmony_ci	struct {
105462306a36Sopenharmony_ci		SVGA3dCmdHeader header;
105562306a36Sopenharmony_ci		SVGA3dCmdDXSetVertexBuffers body;
105662306a36Sopenharmony_ci	} *cmd;
105762306a36Sopenharmony_ci	size_t cmd_size, set_vb_size;
105862306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	vmw_collect_dirty_vbs(cbs, loc, cbs->dirty_vb,
106162306a36Sopenharmony_ci			     SVGA3D_DX_MAX_VERTEXBUFFERS);
106262306a36Sopenharmony_ci	if (cbs->bind_cmd_count == 0)
106362306a36Sopenharmony_ci		return 0;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	set_vb_size = cbs->bind_cmd_count*sizeof(SVGA3dVertexBuffer);
106662306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + set_vb_size;
106762306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
106862306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
106962306a36Sopenharmony_ci		return -ENOMEM;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS;
107262306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + set_vb_size;
107362306a36Sopenharmony_ci	cmd->body.startBuffer = cbs->bind_first_slot;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, set_vb_size);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
107862306a36Sopenharmony_ci	bitmap_clear(cbs->dirty_vb,
107962306a36Sopenharmony_ci		     cbs->bind_first_slot, cbs->bind_cmd_count);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return 0;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic int vmw_emit_set_uav(struct vmw_ctx_binding_state *cbs)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_view *loc = &cbs->ua_views[0].views[0];
108762306a36Sopenharmony_ci	struct {
108862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
108962306a36Sopenharmony_ci		SVGA3dCmdDXSetUAViews body;
109062306a36Sopenharmony_ci	} *cmd;
109162306a36Sopenharmony_ci	size_t cmd_size, view_id_size;
109262306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	vmw_collect_view_ids(cbs, loc, vmw_max_num_uavs(cbs->dev_priv));
109562306a36Sopenharmony_ci	view_id_size = cbs->bind_cmd_count*sizeof(uint32);
109662306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + view_id_size;
109762306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
109862306a36Sopenharmony_ci	if (!cmd)
109962306a36Sopenharmony_ci		return -ENOMEM;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_UA_VIEWS;
110262306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + view_id_size;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/* Splice index is specified user-space   */
110562306a36Sopenharmony_ci	cmd->body.uavSpliceIndex = cbs->ua_views[0].index;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	return 0;
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int vmw_emit_set_cs_uav(struct vmw_ctx_binding_state *cbs)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	const struct vmw_ctx_bindinfo_view *loc = &cbs->ua_views[1].views[0];
111762306a36Sopenharmony_ci	struct {
111862306a36Sopenharmony_ci		SVGA3dCmdHeader header;
111962306a36Sopenharmony_ci		SVGA3dCmdDXSetCSUAViews body;
112062306a36Sopenharmony_ci	} *cmd;
112162306a36Sopenharmony_ci	size_t cmd_size, view_id_size;
112262306a36Sopenharmony_ci	const struct vmw_resource *ctx = vmw_cbs_context(cbs);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	vmw_collect_view_ids(cbs, loc, vmw_max_num_uavs(cbs->dev_priv));
112562306a36Sopenharmony_ci	view_id_size = cbs->bind_cmd_count*sizeof(uint32);
112662306a36Sopenharmony_ci	cmd_size = sizeof(*cmd) + view_id_size;
112762306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(ctx->dev_priv, cmd_size, ctx->id);
112862306a36Sopenharmony_ci	if (!cmd)
112962306a36Sopenharmony_ci		return -ENOMEM;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_CS_UA_VIEWS;
113262306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body) + view_id_size;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* Start index is specified user-space */
113562306a36Sopenharmony_ci	cmd->body.startIndex = cbs->ua_views[1].index;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	vmw_cmd_commit(ctx->dev_priv, cmd_size);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	return 0;
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci/**
114562306a36Sopenharmony_ci * vmw_binding_emit_dirty - Issue delayed binding commands
114662306a36Sopenharmony_ci *
114762306a36Sopenharmony_ci * @cbs: Pointer to the context's struct vmw_ctx_binding_state
114862306a36Sopenharmony_ci *
114962306a36Sopenharmony_ci * This function issues the delayed binding commands that arise from
115062306a36Sopenharmony_ci * previous scrub / unscrub calls. These binding commands are typically
115162306a36Sopenharmony_ci * commands that batch a number of bindings and therefore it makes sense
115262306a36Sopenharmony_ci * to delay them.
115362306a36Sopenharmony_ci */
115462306a36Sopenharmony_cistatic int vmw_binding_emit_dirty(struct vmw_ctx_binding_state *cbs)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	int ret = 0;
115762306a36Sopenharmony_ci	unsigned long hit = 0;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	while ((hit = find_next_bit(&cbs->dirty, VMW_BINDING_NUM_BITS, hit))
116062306a36Sopenharmony_ci	      < VMW_BINDING_NUM_BITS) {
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci		switch (hit) {
116362306a36Sopenharmony_ci		case VMW_BINDING_RT_BIT:
116462306a36Sopenharmony_ci			ret = vmw_emit_set_rt(cbs);
116562306a36Sopenharmony_ci			break;
116662306a36Sopenharmony_ci		case VMW_BINDING_PS_BIT:
116762306a36Sopenharmony_ci			ret = vmw_binding_emit_dirty_ps(cbs);
116862306a36Sopenharmony_ci			break;
116962306a36Sopenharmony_ci		case VMW_BINDING_SO_T_BIT:
117062306a36Sopenharmony_ci			ret = vmw_emit_set_so_target(cbs);
117162306a36Sopenharmony_ci			break;
117262306a36Sopenharmony_ci		case VMW_BINDING_VB_BIT:
117362306a36Sopenharmony_ci			ret = vmw_emit_set_vb(cbs);
117462306a36Sopenharmony_ci			break;
117562306a36Sopenharmony_ci		case VMW_BINDING_UAV_BIT:
117662306a36Sopenharmony_ci			ret = vmw_emit_set_uav(cbs);
117762306a36Sopenharmony_ci			break;
117862306a36Sopenharmony_ci		case VMW_BINDING_CS_UAV_BIT:
117962306a36Sopenharmony_ci			ret = vmw_emit_set_cs_uav(cbs);
118062306a36Sopenharmony_ci			break;
118162306a36Sopenharmony_ci		default:
118262306a36Sopenharmony_ci			BUG();
118362306a36Sopenharmony_ci		}
118462306a36Sopenharmony_ci		if (ret)
118562306a36Sopenharmony_ci			return ret;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci		__clear_bit(hit, &cbs->dirty);
118862306a36Sopenharmony_ci		hit++;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return 0;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci/**
119562306a36Sopenharmony_ci * vmw_binding_scrub_sr - Schedule a dx shaderresource binding
119662306a36Sopenharmony_ci * scrub from a context
119762306a36Sopenharmony_ci *
119862306a36Sopenharmony_ci * @bi: single binding information.
119962306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
120062306a36Sopenharmony_ci */
120162306a36Sopenharmony_cistatic int vmw_binding_scrub_sr(struct vmw_ctx_bindinfo *bi, bool rebind)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_view *biv =
120462306a36Sopenharmony_ci		container_of(bi, struct vmw_ctx_bindinfo_view, bi);
120562306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs =
120662306a36Sopenharmony_ci		vmw_context_binding_state(bi->ctx);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	__set_bit(biv->slot, cbs->per_shader[biv->shader_slot].dirty_sr);
120962306a36Sopenharmony_ci	__set_bit(VMW_BINDING_PS_SR_BIT,
121062306a36Sopenharmony_ci		  &cbs->per_shader[biv->shader_slot].dirty);
121162306a36Sopenharmony_ci	__set_bit(VMW_BINDING_PS_BIT, &cbs->dirty);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return 0;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci/**
121762306a36Sopenharmony_ci * vmw_binding_scrub_dx_rt - Schedule a dx rendertarget binding
121862306a36Sopenharmony_ci * scrub from a context
121962306a36Sopenharmony_ci *
122062306a36Sopenharmony_ci * @bi: single binding information.
122162306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
122262306a36Sopenharmony_ci */
122362306a36Sopenharmony_cistatic int vmw_binding_scrub_dx_rt(struct vmw_ctx_bindinfo *bi, bool rebind)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs =
122662306a36Sopenharmony_ci		vmw_context_binding_state(bi->ctx);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	__set_bit(VMW_BINDING_RT_BIT, &cbs->dirty);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	return 0;
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/**
123462306a36Sopenharmony_ci * vmw_binding_scrub_so_target - Schedule a dx streamoutput buffer binding
123562306a36Sopenharmony_ci * scrub from a context
123662306a36Sopenharmony_ci *
123762306a36Sopenharmony_ci * @bi: single binding information.
123862306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
123962306a36Sopenharmony_ci */
124062306a36Sopenharmony_cistatic int vmw_binding_scrub_so_target(struct vmw_ctx_bindinfo *bi, bool rebind)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs =
124362306a36Sopenharmony_ci		vmw_context_binding_state(bi->ctx);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	__set_bit(VMW_BINDING_SO_T_BIT, &cbs->dirty);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/**
125162306a36Sopenharmony_ci * vmw_binding_scrub_vb - Schedule a dx vertex buffer binding
125262306a36Sopenharmony_ci * scrub from a context
125362306a36Sopenharmony_ci *
125462306a36Sopenharmony_ci * @bi: single binding information.
125562306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
125662306a36Sopenharmony_ci */
125762306a36Sopenharmony_cistatic int vmw_binding_scrub_vb(struct vmw_ctx_bindinfo *bi, bool rebind)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_vb *bivb =
126062306a36Sopenharmony_ci		container_of(bi, struct vmw_ctx_bindinfo_vb, bi);
126162306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs =
126262306a36Sopenharmony_ci		vmw_context_binding_state(bi->ctx);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	__set_bit(bivb->slot, cbs->dirty_vb);
126562306a36Sopenharmony_ci	__set_bit(VMW_BINDING_VB_BIT, &cbs->dirty);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	return 0;
126862306a36Sopenharmony_ci}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci/**
127162306a36Sopenharmony_ci * vmw_binding_scrub_ib - scrub a dx index buffer binding from a context
127262306a36Sopenharmony_ci *
127362306a36Sopenharmony_ci * @bi: single binding information.
127462306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
127562306a36Sopenharmony_ci */
127662306a36Sopenharmony_cistatic int vmw_binding_scrub_ib(struct vmw_ctx_bindinfo *bi, bool rebind)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_ib *binding =
127962306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
128062306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
128162306a36Sopenharmony_ci	struct {
128262306a36Sopenharmony_ci		SVGA3dCmdHeader header;
128362306a36Sopenharmony_ci		SVGA3dCmdDXSetIndexBuffer body;
128462306a36Sopenharmony_ci	} *cmd;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), bi->ctx->id);
128762306a36Sopenharmony_ci	if (unlikely(cmd == NULL))
128862306a36Sopenharmony_ci		return -ENOMEM;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_INDEX_BUFFER;
129162306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
129262306a36Sopenharmony_ci	if (rebind) {
129362306a36Sopenharmony_ci		cmd->body.sid = bi->res->id;
129462306a36Sopenharmony_ci		cmd->body.format = binding->format;
129562306a36Sopenharmony_ci		cmd->body.offset = binding->offset;
129662306a36Sopenharmony_ci	} else {
129762306a36Sopenharmony_ci		cmd->body.sid = SVGA3D_INVALID_ID;
129862306a36Sopenharmony_ci		cmd->body.format = 0;
129962306a36Sopenharmony_ci		cmd->body.offset = 0;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	return 0;
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic int vmw_binding_scrub_uav(struct vmw_ctx_bindinfo *bi, bool rebind)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs = vmw_context_binding_state(bi->ctx);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	__set_bit(VMW_BINDING_UAV_BIT, &cbs->dirty);
131262306a36Sopenharmony_ci	return 0;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int vmw_binding_scrub_cs_uav(struct vmw_ctx_bindinfo *bi, bool rebind)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs = vmw_context_binding_state(bi->ctx);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	__set_bit(VMW_BINDING_CS_UAV_BIT, &cbs->dirty);
132062306a36Sopenharmony_ci	return 0;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci/**
132462306a36Sopenharmony_ci * vmw_binding_scrub_so - Scrub a streamoutput binding from context.
132562306a36Sopenharmony_ci * @bi: Single binding information.
132662306a36Sopenharmony_ci * @rebind: Whether to issue a bind instead of scrub command.
132762306a36Sopenharmony_ci */
132862306a36Sopenharmony_cistatic int vmw_binding_scrub_so(struct vmw_ctx_bindinfo *bi, bool rebind)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	struct vmw_ctx_bindinfo_so *binding =
133162306a36Sopenharmony_ci		container_of(bi, typeof(*binding), bi);
133262306a36Sopenharmony_ci	struct vmw_private *dev_priv = bi->ctx->dev_priv;
133362306a36Sopenharmony_ci	struct {
133462306a36Sopenharmony_ci		SVGA3dCmdHeader header;
133562306a36Sopenharmony_ci		SVGA3dCmdDXSetStreamOutput body;
133662306a36Sopenharmony_ci	} *cmd;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), bi->ctx->id);
133962306a36Sopenharmony_ci	if (!cmd)
134062306a36Sopenharmony_ci		return -ENOMEM;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_SET_STREAMOUTPUT;
134362306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
134462306a36Sopenharmony_ci	cmd->body.soid = rebind ? bi->res->id : SVGA3D_INVALID_ID;
134562306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	return 0;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci/**
135162306a36Sopenharmony_ci * vmw_binding_state_alloc - Allocate a struct vmw_ctx_binding_state.
135262306a36Sopenharmony_ci *
135362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private structure.
135462306a36Sopenharmony_ci *
135562306a36Sopenharmony_ci * Returns a pointer to a newly allocated struct or an error pointer on error.
135662306a36Sopenharmony_ci */
135762306a36Sopenharmony_cistruct vmw_ctx_binding_state *
135862306a36Sopenharmony_civmw_binding_state_alloc(struct vmw_private *dev_priv)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct vmw_ctx_binding_state *cbs;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	cbs = vzalloc(sizeof(*cbs));
136362306a36Sopenharmony_ci	if (!cbs) {
136462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	cbs->dev_priv = dev_priv;
136862306a36Sopenharmony_ci	INIT_LIST_HEAD(&cbs->list);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	return cbs;
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci/**
137462306a36Sopenharmony_ci * vmw_binding_state_free - Free a struct vmw_ctx_binding_state.
137562306a36Sopenharmony_ci *
137662306a36Sopenharmony_ci * @cbs: Pointer to the struct vmw_ctx_binding_state to be freed.
137762306a36Sopenharmony_ci */
137862306a36Sopenharmony_civoid vmw_binding_state_free(struct vmw_ctx_binding_state *cbs)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	vfree(cbs);
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci/**
138462306a36Sopenharmony_ci * vmw_binding_state_list - Get the binding list of a
138562306a36Sopenharmony_ci * struct vmw_ctx_binding_state
138662306a36Sopenharmony_ci *
138762306a36Sopenharmony_ci * @cbs: Pointer to the struct vmw_ctx_binding_state
138862306a36Sopenharmony_ci *
138962306a36Sopenharmony_ci * Returns the binding list which can be used to traverse through the bindings
139062306a36Sopenharmony_ci * and access the resource information of all bindings.
139162306a36Sopenharmony_ci */
139262306a36Sopenharmony_cistruct list_head *vmw_binding_state_list(struct vmw_ctx_binding_state *cbs)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	return &cbs->list;
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/**
139862306a36Sopenharmony_ci * vmw_binding_state_reset - clear a struct vmw_ctx_binding_state
139962306a36Sopenharmony_ci *
140062306a36Sopenharmony_ci * @cbs: Pointer to the struct vmw_ctx_binding_state to be cleared
140162306a36Sopenharmony_ci *
140262306a36Sopenharmony_ci * Drops all bindings registered in @cbs. No device binding actions are
140362306a36Sopenharmony_ci * performed.
140462306a36Sopenharmony_ci */
140562306a36Sopenharmony_civoid vmw_binding_state_reset(struct vmw_ctx_binding_state *cbs)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	struct vmw_ctx_bindinfo *entry, *next;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
141062306a36Sopenharmony_ci		vmw_binding_drop(entry);
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci/**
141462306a36Sopenharmony_ci * vmw_binding_dirtying - Return whether a binding type is dirtying its resource
141562306a36Sopenharmony_ci * @binding_type: The binding type
141662306a36Sopenharmony_ci *
141762306a36Sopenharmony_ci * Each time a resource is put on the validation list as the result of a
141862306a36Sopenharmony_ci * context binding referencing it, we need to determine whether that resource
141962306a36Sopenharmony_ci * will be dirtied (written to by the GPU) as a result of the corresponding
142062306a36Sopenharmony_ci * GPU operation. Currently rendertarget-, depth-stencil-, stream-output-target
142162306a36Sopenharmony_ci * and unordered access view bindings are capable of dirtying its resource.
142262306a36Sopenharmony_ci *
142362306a36Sopenharmony_ci * Return: Whether the binding type dirties the resource its binding points to.
142462306a36Sopenharmony_ci */
142562306a36Sopenharmony_ciu32 vmw_binding_dirtying(enum vmw_ctx_binding_type binding_type)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	static u32 is_binding_dirtying[vmw_ctx_binding_max] = {
142862306a36Sopenharmony_ci		[vmw_ctx_binding_rt] = VMW_RES_DIRTY_SET,
142962306a36Sopenharmony_ci		[vmw_ctx_binding_dx_rt] = VMW_RES_DIRTY_SET,
143062306a36Sopenharmony_ci		[vmw_ctx_binding_ds] = VMW_RES_DIRTY_SET,
143162306a36Sopenharmony_ci		[vmw_ctx_binding_so_target] = VMW_RES_DIRTY_SET,
143262306a36Sopenharmony_ci		[vmw_ctx_binding_uav] = VMW_RES_DIRTY_SET,
143362306a36Sopenharmony_ci		[vmw_ctx_binding_cs_uav] = VMW_RES_DIRTY_SET,
143462306a36Sopenharmony_ci	};
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* Review this function as new bindings are added. */
143762306a36Sopenharmony_ci	BUILD_BUG_ON(vmw_ctx_binding_max != 14);
143862306a36Sopenharmony_ci	return is_binding_dirtying[binding_type];
143962306a36Sopenharmony_ci}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci/*
144262306a36Sopenharmony_ci * This function is unused at run-time, and only used to hold various build
144362306a36Sopenharmony_ci * asserts important for code optimization assumptions.
144462306a36Sopenharmony_ci */
144562306a36Sopenharmony_cistatic void vmw_binding_build_asserts(void)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	BUILD_BUG_ON(SVGA3D_NUM_SHADERTYPE_DX10 != 3);
144862306a36Sopenharmony_ci	BUILD_BUG_ON(SVGA3D_DX_MAX_RENDER_TARGETS > SVGA3D_RT_MAX);
144962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(uint32) != sizeof(u32));
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/*
145262306a36Sopenharmony_ci	 * struct vmw_ctx_binding_state::bind_cmd_buffer is used for various
145362306a36Sopenharmony_ci	 * view id arrays.
145462306a36Sopenharmony_ci	 */
145562306a36Sopenharmony_ci	BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_RT_MAX);
145662306a36Sopenharmony_ci	BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_DX_MAX_SRVIEWS);
145762306a36Sopenharmony_ci	BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_DX_MAX_CONSTBUFFERS);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	/*
146062306a36Sopenharmony_ci	 * struct vmw_ctx_binding_state::bind_cmd_buffer is used for
146162306a36Sopenharmony_ci	 * u32 view ids, SVGA3dSoTargets and SVGA3dVertexBuffers
146262306a36Sopenharmony_ci	 */
146362306a36Sopenharmony_ci	BUILD_BUG_ON(SVGA3D_DX_MAX_SOTARGETS*sizeof(SVGA3dSoTarget) >
146462306a36Sopenharmony_ci		     VMW_MAX_VIEW_BINDINGS*sizeof(u32));
146562306a36Sopenharmony_ci	BUILD_BUG_ON(SVGA3D_DX_MAX_VERTEXBUFFERS*sizeof(SVGA3dVertexBuffer) >
146662306a36Sopenharmony_ci		     VMW_MAX_VIEW_BINDINGS*sizeof(u32));
146762306a36Sopenharmony_ci}
1468