Post by Stefan Dösinger1) 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.
Post by Stefan Dösinger2) 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.
Post by Stefan Dösinger3) 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.
Post by Stefan Dösinger4) 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.
Post by Stefan Dösinger5) 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.
Post by Stefan DösingerI 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.
Post by Stefan Dösinger*) 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.
Post by Stefan Dösinger*) 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.