Support sampler states in tinyGL renderer

This commit is contained in:
rdb 2014-12-12 20:32:36 +01:00
parent 89031b4e48
commit 8a5452b0b6
2 changed files with 65 additions and 46 deletions

View File

@ -34,6 +34,7 @@
#include "lightAttrib.h" #include "lightAttrib.h"
#include "scissorAttrib.h" #include "scissorAttrib.h"
#include "bitMask.h" #include "bitMask.h"
#include "samplerState.h"
#include "zgl.h" #include "zgl.h"
#include "zmath.h" #include "zmath.h"
#include "ztriangle_table.h" #include "ztriangle_table.h"
@ -118,7 +119,7 @@ reset() {
_c->draw_triangle_back = gl_draw_triangle_fill; _c->draw_triangle_back = gl_draw_triangle_fill;
_supported_geom_rendering = _supported_geom_rendering =
Geom::GR_point | Geom::GR_point |
Geom::GR_indexed_other | Geom::GR_indexed_other |
Geom::GR_triangle_strip | Geom::GR_triangle_strip |
Geom::GR_flat_last_vertex; Geom::GR_flat_last_vertex;
@ -568,7 +569,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
} }
// Compose the modelview and projection matrices. // Compose the modelview and projection matrices.
load_matrix(&_c->matrix_model_projection, load_matrix(&_c->matrix_model_projection,
scissor_proj_mat->compose(_internal_transform)); scissor_proj_mat->compose(_internal_transform));
/* test to accelerate computation */ /* test to accelerate computation */
@ -658,7 +659,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
{ {
CPT(TransformState) render_transform = CPT(TransformState) render_transform =
_cs_transform->compose(_scene_setup->get_world_transform()); _cs_transform->compose(_scene_setup->get_world_transform());
CPT(TransformState) world_inv_transform = CPT(TransformState) world_inv_transform =
render_transform->invert_compose(_internal_transform); render_transform->invert_compose(_internal_transform);
tcdata[si]._mat = world_inv_transform->get_mat(); tcdata[si]._mat = world_inv_transform->get_mat();
} }
@ -709,7 +710,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
needs_normal = rnormal.has_column(); needs_normal = rnormal.has_column();
} }
GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force); GeomVertexReader rvertex(data_reader, InternalName::get_vertex(), force);
rvertex.set_row_unsafe(_min_vertex); rvertex.set_row_unsafe(_min_vertex);
if (!rvertex.has_column()) { if (!rvertex.has_column()) {
@ -1717,10 +1718,11 @@ update_texture(TextureContext *tc, bool force) {
if (gtc->was_image_modified() || gltex->num_levels == 0) { if (gtc->was_image_modified() || gltex->num_levels == 0) {
// If the texture image was modified, reload the texture. // If the texture image was modified, reload the texture.
bool okflag = upload_texture(gtc, force); Texture *tex = gtc->get_texture();
bool okflag = upload_texture(gtc, force, tex->uses_mipmaps());
if (!okflag) { if (!okflag) {
tinydisplay_cat.error() tinydisplay_cat.error()
<< "Could not load " << *gtc->get_texture() << "\n"; << "Could not load " << *tex << "\n";
return false; return false;
} }
} }
@ -1746,7 +1748,7 @@ update_texture(TextureContext *tc, bool force) {
// true). // true).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool TinyGraphicsStateGuardian:: bool TinyGraphicsStateGuardian::
update_texture(TextureContext *tc, bool force, int stage_index) { update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps) {
if (!update_texture(tc, force)) { if (!update_texture(tc, force)) {
return false; return false;
} }
@ -1754,6 +1756,17 @@ update_texture(TextureContext *tc, bool force, int stage_index) {
TinyTextureContext *gtc = DCAST(TinyTextureContext, tc); TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
GLTexture *gltex = &gtc->_gltex; GLTexture *gltex = &gtc->_gltex;
if (uses_mipmaps && gltex->num_levels <= 1) {
// We don't have mipmaps, yet we are sampling with mipmaps.
Texture *tex = gtc->get_texture();
bool okflag = upload_texture(gtc, force, true);
if (!okflag) {
tinydisplay_cat.error()
<< "Could not load " << *tex << "\n";
return false;
}
}
_c->current_textures[stage_index] = gltex; _c->current_textures[stage_index] = gltex;
ZTextureDef *texture_def = &_c->zb->current_textures[stage_index]; ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
@ -1762,13 +1775,13 @@ update_texture(TextureContext *tc, bool force, int stage_index) {
texture_def->t_max = gltex->t_max; texture_def->t_max = gltex->t_max;
const V4 &bc = gltex->border_color; const V4 &bc = gltex->border_color;
int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) int r = (int)(bc.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN)
+ ZB_POINT_RED_MIN); + ZB_POINT_RED_MIN);
int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) int g = (int)(bc.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN)
+ ZB_POINT_GREEN_MIN); + ZB_POINT_GREEN_MIN);
int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) int b = (int)(bc.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN)
+ ZB_POINT_BLUE_MIN); + ZB_POINT_BLUE_MIN);
int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN) int a = (int)(bc.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN)
+ ZB_POINT_ALPHA_MIN); + ZB_POINT_ALPHA_MIN);
texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a); texture_def->border_color = RGBA_TO_PIXEL(r, g, b, a);
@ -1809,7 +1822,7 @@ release_texture(TextureContext *tc) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::do_issue_light // Function: TinyGraphicsStateGuardian::do_issue_light
// Access: Protected, Virtual // Access: Protected, Virtual
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void TinyGraphicsStateGuardian:: void TinyGraphicsStateGuardian::
do_issue_light() { do_issue_light() {
@ -2016,7 +2029,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
gl_light->specular.v[1] = specular[1]; gl_light->specular.v[1] = specular[1];
gl_light->specular.v[2] = specular[2]; gl_light->specular.v[2] = specular[2];
gl_light->specular.v[3] = specular[3]; gl_light->specular.v[3] = specular[3];
Lens *lens = light_obj->get_lens(); Lens *lens = light_obj->get_lens();
nassertv(lens != (Lens *)NULL); nassertv(lens != (Lens *)NULL);
@ -2267,16 +2280,19 @@ do_issue_texture() {
TextureStage *stage = _target_texture->get_on_ff_stage(si); TextureStage *stage = _target_texture->get_on_ff_stage(si);
Texture *texture = _target_texture->get_on_texture(stage); Texture *texture = _target_texture->get_on_texture(stage);
nassertv(texture != (Texture *)NULL); nassertv(texture != (Texture *)NULL);
int view = get_current_tex_view_offset() + stage->get_tex_view_offset(); int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
TextureContext *tc = texture->prepare_now(view, _prepared_objects, this); TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
if (tc == (TextureContext *)NULL) { if (tc == (TextureContext *)NULL) {
// Something wrong with this texture; skip it. // Something wrong with this texture; skip it.
return; return;
} }
// Get the sampler state that we are supposed to use.
const SamplerState &sampler = _target_texture->get_on_sampler(stage);
// Then, turn on the current texture mode. // Then, turn on the current texture mode.
if (!update_texture(tc, false, si)) { if (!update_texture(tc, false, si, sampler.uses_mipmaps())) {
return; return;
} }
@ -2297,13 +2313,13 @@ do_issue_texture() {
best_quality_level = max(best_quality_level, quality_level); best_quality_level = max(best_quality_level, quality_level);
ZTextureDef *texture_def = &_c->zb->current_textures[si]; ZTextureDef *texture_def = &_c->zb->current_textures[si];
// Fill in the filter func pointers. These may not actually get // Fill in the filter func pointers. These may not actually get
// called, if we decide below we can inline the filters. // called, if we decide below we can inline the filters.
SamplerState::FilterType minfilter = texture->get_minfilter(); SamplerState::FilterType minfilter = sampler.get_minfilter();
SamplerState::FilterType magfilter = texture->get_magfilter(); SamplerState::FilterType magfilter = sampler.get_magfilter();
if (td_ignore_mipmaps && Texture::is_mipmap(minfilter)) { if (td_ignore_mipmaps && SamplerState::is_mipmap(minfilter)) {
// Downgrade mipmaps. // Downgrade mipmaps.
if (minfilter == SamplerState::FT_nearest_mipmap_nearest) { if (minfilter == SamplerState::FT_nearest_mipmap_nearest) {
minfilter = SamplerState::FT_nearest; minfilter = SamplerState::FT_nearest;
@ -2319,7 +2335,7 @@ do_issue_texture() {
magfilter = SamplerState::FT_nearest; magfilter = SamplerState::FT_nearest;
} else if (quality_level == Texture::QL_normal) { } else if (quality_level == Texture::QL_normal) {
if (Texture::is_mipmap(minfilter)) { if (SamplerState::is_mipmap(minfilter)) {
minfilter = SamplerState::FT_nearest_mipmap_nearest; minfilter = SamplerState::FT_nearest_mipmap_nearest;
} else { } else {
minfilter = SamplerState::FT_nearest; minfilter = SamplerState::FT_nearest;
@ -2327,15 +2343,15 @@ do_issue_texture() {
magfilter = SamplerState::FT_nearest; magfilter = SamplerState::FT_nearest;
} else if (quality_level == Texture::QL_best) { } else if (quality_level == Texture::QL_best) {
minfilter = texture->get_effective_minfilter(); minfilter = sampler.get_effective_minfilter();
magfilter = texture->get_effective_magfilter(); magfilter = sampler.get_effective_magfilter();
} }
texture_def->tex_minfilter_func = get_tex_filter_func(minfilter); texture_def->tex_minfilter_func = get_tex_filter_func(minfilter);
texture_def->tex_magfilter_func = get_tex_filter_func(magfilter); texture_def->tex_magfilter_func = get_tex_filter_func(magfilter);
SamplerState::WrapMode wrap_u = texture->get_wrap_u(); SamplerState::WrapMode wrap_u = sampler.get_wrap_u();
SamplerState::WrapMode wrap_v = texture->get_wrap_v(); SamplerState::WrapMode wrap_v = sampler.get_wrap_v();
if (td_ignore_clamp) { if (td_ignore_clamp) {
wrap_u = SamplerState::WM_repeat; wrap_u = SamplerState::WM_repeat;
wrap_v = SamplerState::WM_repeat; wrap_v = SamplerState::WM_repeat;
@ -2382,7 +2398,7 @@ do_issue_texture() {
all_mipmap_nearest = false; all_mipmap_nearest = false;
} }
if (Texture::is_mipmap(minfilter)) { if (SamplerState::is_mipmap(minfilter)) {
any_mipmap = true; any_mipmap = true;
} }
} }
@ -2419,7 +2435,7 @@ do_issue_texture() {
// perspective correctness. // perspective correctness.
_texfilter_state = 0; // tnearest _texfilter_state = 0; // tnearest
_texturing_state = 1; // textured (not perspective correct, no multitexture) _texturing_state = 1; // textured (not perspective correct, no multitexture)
} else { } else {
// This is the default texture filter. We use nearest sampling if // This is the default texture filter. We use nearest sampling if
// there are no mipmaps, and mipmap_nearest if there are any // there are no mipmaps, and mipmap_nearest if there are any
@ -2500,7 +2516,7 @@ apply_texture(TextureContext *tc) {
// the texture has no image. // the texture has no image.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool TinyGraphicsStateGuardian:: bool TinyGraphicsStateGuardian::
upload_texture(TinyTextureContext *gtc, bool force) { upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps) {
Texture *tex = gtc->get_texture(); Texture *tex = gtc->get_texture();
if (_effective_incomplete_render && !force) { if (_effective_incomplete_render && !force) {
@ -2525,21 +2541,24 @@ upload_texture(TinyTextureContext *gtc, bool force) {
return false; return false;
} }
if (tinydisplay_cat.is_debug()) {
tinydisplay_cat.debug()
<< "loading texture " << tex->get_name() << "\n";
}
#ifdef DO_PSTATS #ifdef DO_PSTATS
_data_transferred_pcollector.add_level(tex->get_ram_image_size()); _data_transferred_pcollector.add_level(tex->get_ram_image_size());
#endif #endif
GLTexture *gltex = &gtc->_gltex; GLTexture *gltex = &gtc->_gltex;
int num_levels = 1; int num_levels = 1;
if (tex->uses_mipmaps()) { if (uses_mipmaps) {
if (!tex->has_all_ram_mipmap_images()) { num_levels = tex->get_expected_num_mipmap_levels();
if (tex->get_num_ram_mipmap_images() < num_levels) {
tex->generate_ram_mipmap_images(); tex->generate_ram_mipmap_images();
} }
num_levels = tex->get_num_ram_mipmap_images(); }
if (tinydisplay_cat.is_debug()) {
tinydisplay_cat.debug()
<< "loading texture " << tex->get_name() << ", "
<< tex->get_x_size() << " x " << tex->get_y_size() << ", mipmaps = "
<< num_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
} }
if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) { if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) {
@ -2616,7 +2635,7 @@ upload_texture(TinyTextureContext *gtc, bool force) {
} }
gtc->update_data_size_bytes(bytecount); gtc->update_data_size_bytes(bytecount);
get_engine()->texture_uploaded(tex); get_engine()->texture_uploaded(tex);
gtc->mark_loaded(); gtc->mark_loaded();
@ -2687,7 +2706,7 @@ bool TinyGraphicsStateGuardian::
setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) { setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
int s_bits = get_tex_shift(x_size); int s_bits = get_tex_shift(x_size);
int t_bits = get_tex_shift(y_size); int t_bits = get_tex_shift(y_size);
if (s_bits < 0 || t_bits < 0) { if (s_bits < 0 || t_bits < 0) {
return false; return false;
} }
@ -2701,7 +2720,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
gltex->t_max = 1 << (t_bits + ZB_POINT_ST_FRAC_BITS); gltex->t_max = 1 << (t_bits + ZB_POINT_ST_FRAC_BITS);
gltex->num_levels = num_levels; gltex->num_levels = num_levels;
// We allocate one big buffer, large enough to include all the // We allocate one big buffer, large enough to include all the
// mipmap levels, and index into that buffer for each level. This // mipmap levels, and index into that buffer for each level. This
// cuts down on the number of individual alloc calls we have to make // cuts down on the number of individual alloc calls we have to make
@ -2746,7 +2765,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level; dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level); dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level); dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
x_size = max((x_size >> 1), 1); x_size = max((x_size >> 1), 1);
y_size = max((y_size >> 1), 1); y_size = max((y_size >> 1), 1);
s_bits = max(s_bits - 1, 0); s_bits = max(s_bits - 1, 0);
@ -3187,7 +3206,7 @@ get_color_blend_op(ColorBlendAttrib::Operand operand) {
} }
return 0; return 0;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::get_tex_filter_func // Function: TinyGraphicsStateGuardian::get_tex_filter_func
// Access: Private, Static // Access: Private, Static
@ -3208,7 +3227,7 @@ get_tex_filter_func(SamplerState::FilterType filter) {
case SamplerState::FT_nearest_mipmap_linear: case SamplerState::FT_nearest_mipmap_linear:
return &lookup_texture_mipmap_linear; return &lookup_texture_mipmap_linear;
case SamplerState::FT_linear_mipmap_nearest: case SamplerState::FT_linear_mipmap_nearest:
return &lookup_texture_mipmap_bilinear; return &lookup_texture_mipmap_bilinear;
@ -3219,7 +3238,7 @@ get_tex_filter_func(SamplerState::FilterType filter) {
return &lookup_texture_nearest; return &lookup_texture_nearest;
} }
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::get_tex_wrap_func // Function: TinyGraphicsStateGuardian::get_tex_wrap_func
// Access: Private, Static // Access: Private, Static
@ -3305,7 +3324,7 @@ texgen_sphere_map(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) {
// Compute the reflection vector. // Compute the reflection vector.
LVector3 r = u - n * dot(n, u) * 2.0f; LVector3 r = u - n * dot(n, u) * 2.0f;
// compute the denominator, m. // compute the denominator, m.
PN_stdfloat m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f)); PN_stdfloat m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f));

View File

@ -91,7 +91,7 @@ public:
virtual TextureContext *prepare_texture(Texture *tex, int view); virtual TextureContext *prepare_texture(Texture *tex, int view);
virtual bool update_texture(TextureContext *tc, bool force); virtual bool update_texture(TextureContext *tc, bool force);
bool update_texture(TextureContext *tc, bool force, int stage_index); bool update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps);
virtual void release_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc);
virtual void do_issue_light(); virtual void do_issue_light();
@ -115,7 +115,7 @@ private:
void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top); void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top);
bool apply_texture(TextureContext *tc); bool apply_texture(TextureContext *tc);
bool upload_texture(TinyTextureContext *gtc, bool force); bool upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps);
bool upload_simple_texture(TinyTextureContext *gtc); bool upload_simple_texture(TinyTextureContext *gtc);
bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels); bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels);
int get_tex_shift(int orig_size); int get_tex_shift(int orig_size);