WineD3D: WineD3D: Use the shader backend to enable / disable atifs and nvts

H. Verbeet hverbeet at gmail.com
Fri Apr 11 15:42:17 CDT 2008


On 11/04/2008, Stefan Dösinger <stefan at codeweavers.com> wrote:
>  1) The state table should be selectable based on the available opengl features
>  and possibly registry settings. I think we all agree on that
>
Up to the level of being able to use different state handlers in
different situations. I don't necessarily agree with copying and
swapping the entire table in one piece.

>  2) We want a fixed function vertex and fragment pipeline replacement with ARB
>  and GLSL
>
Only GLSL is a requirement for me. ARB could be nice, but is probably redundant.

>  3) We want to be able to support pixel shaders with atifs and nvts. I don't
>  know if that will ever be implemented, but if we choose a design that makes
>  this hard or impossible that's not going to help
>
This is not a hard requirement for me, although I certainly think we
should be able to create a design that allows for this.

>  4) Even if we have an ARB/GLSL replacement, it should be possible to use D3D
>  shaders but still use the opengl fixed function pipeline
>
Agreed.

>  5) A nice to have is to be able to use the replacement pipelines together with
>  shaders, but that is not a hard requirement for me. We need an ARB and GLSL
>  replacement anyway.
>
I assume you mean atifs & nvrc specifically here, in which case this
is probably a bit more important than "nice to have". The most tricky
situation to support here will be cards that support vertex shaders,
but not fragment shaders. If we want to support pixel shaders using
atifs / nvrc we have to allow mixing GLSL / ARB with nvrc / atifs for
it to be of any use.


>  I understand Henri's suggestion this way: Don't put the state table into the
>  shader backend(*), but select it separately. This way the ATIFS pipeline
>  replacement doesn't have to be a shader model. That way we can choose the ARB
>  shader backend and ATIFS state table on r200 cards, and use GLSL and ATIFS on
>  newer cards.
>
>  That way we get full shader support and still the advantages of the pipeline
>  replacement without using 3 inherited shader backends. Then the state table
>  could have some backend to enable / disable ATIFS like in this patch. (The
>  bottom line of the patch here is that we should enable the extension we
>  *use*, and not what happens to be available).
>
>  The state table would report the fixed function caps it has, and the shader
>  backend reports the programmable pipeline caps. GetDeviceCaps has to collect
>  the caps from multiple places, but that isn't an issue IMO.
>
>  Is that correct, or did I missunderstand something?
>
My main point is that a fixed function replacement and the shader
backend should be two different things, at least interface wise. My
suggestion for an implementation would be somethingg like this:

  - Split the state table in three pieces: vertex processing states
(eg. lighting, materials, etc), fragment processing states (eg.
texture stage stuff) and other states (eg. blending states). Aside
from being clearer this allows you to swap these parts out
independently from each other and possibly skip applying them as a
whole in case a shader is active for that part of the pipeline (I
imagine this could have some performance advantages as well, although
I'm not sure how much).
  - Allow the state table more explicitly to have some state of its
own. It currently has the list of dirty states of course, but it's
more managed by the device than by the statetable as such. In effect
this would introduce a state management object.

The basic setup would be something like this:

struct shader_backend_t
{
    void (*shader_select)(void *data, BOOL usePS, BOOL useVS);
    void (*shader_load_constants)(void *data, char usePS, char useVS);
    ...
};

struct state_management_t
{
    void (*mark_state_dirty)(void *data, DWORD state);
    void (*apply_states)(void *data);
    ...
};

struct IWineD3DDeviceImpl {
    ...
    struct state_management_t vertex_state_manager;
    struct state_management_t fragment_state_manager;
    struct state_management_t other_state_manager;
    struct shader_backend_t shader_backend;

    void *vertex_private_data;
    void *fragment_private_data;
    void *other_private_data;
    void *shader_private_data;
    ...
};

/* Usage */
device->vertex_state_manager->mark_state_dirty(device->vertex_private_data,
state);
device->fragment_state_manager->mark_state_dirty(device->fragment_private_data,
state);
etc.
...
if (!use_vs) {
	device->vertex_state_manager->apply_states(device->vertex_private_data);
}
if (!use_ps) {
	device->fragment_state_manager->apply_states(device->fragment_private_data);
}
device->shader_backend->select_shader(device->shader_private_date,
use_vs, use_ps);


Some example configurations:

GLSL FFP, GLSL shaders
	device = {glsl_vsm, glsl_fsm, ff_osm, glsl_shader_backend,
glsl_private_data, glsl_private_data, ff_private_data,
glsl_private_data};

Fixed function vertex, ATIFS fragment processing, GLSL shader backend
	device = {ff_vsm, atifs_fsm, ff_osm, glsl_shader_backend,
ff_private_data, atifs_private_data, ff_private_data,
glsl_private_data};

ARB vertex FFP, Fixed function fragment, ARB shaders
	device = arb_vsm, ff_fsm, ff_osm, arb_shader_backend,
arb_ffp_private_data, ff_private_data, ff_private_data,
arb_shader_private_data};

This doesn't support mixing eg. ARB vertex shaders with NVRC pixel
shaders, but it would "simply" be a matter of splitting up the shader
backend in a similar way to the state table. Important to note here is
that the private data could be shared between fixed function
replacements and the shader backend, like in the case of GLSL. I could
imagine using a structure more similar to state_management_t for the
shader backend as well.

Of course there are a number of variations you can make on this
(perhaps most notably storing the call tables and private data in the
same struct), but I think the important parts are the split between
vertex/fragment/other/shader, and the state management having private
data.

>  However, I see two issues with that:
>
>  *) In which place do we decide which program/shader to use in the end? If we
>  have an ARB fixed function replacement program and an ARB program generated
>  from a D3D shader? Currently this happens to work because ARB/GLSL override
>  NVTS and NVRC, but this fails if we have a shader and ffp implementation
>  using the same extension
>
The private data between the FFP replacement and the shader backend
can be shared. That means our general GLSL management stuff can see
you've got eg. a FFP vertex shader and a pixel shader and link them
together.

>  *) What do we do if a shader implementation wants to overwrite some states for
>  its programmable pipeline work? For example take my GLSL clipplane patch: The
>  ARB shader backend disables clipplanes when a shader is used. This example is
>  about a driver bug, but there are others as well: ATIFS and NVTS with a pixel
>  shader implementation will have to override a part of the sampler setting(the
>  stuff that is currently done in activate_dimensions)
>
>  How would you deal with this?
>
I guess this will mostly be an issue for states that end up being in
the "other" category. In general I think that as long as it's only for
a couple of states we can just keep doing more or less what we
currently do and check if the relevant state management backend is
used.



More information about the wine-devel mailing list