/*
|
* Copyright (C) 2009 Francisco Jerez.
|
* All Rights Reserved.
|
*
|
* Permission is hereby granted, free of charge, to any person obtaining
|
* a copy of this software and associated documentation files (the
|
* "Software"), to deal in the Software without restriction, including
|
* without limitation the rights to use, copy, modify, merge, publish,
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
* permit persons to whom the Software is furnished to do so, subject to
|
* the following conditions:
|
*
|
* The above copyright notice and this permission notice (including the
|
* next paragraph) shall be included in all copies or substantial
|
* portions of the Software.
|
*
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
*
|
*/
|
|
#include "nouveau_driver.h"
|
#include "nouveau_context.h"
|
#include "nouveau_texture.h"
|
#include "nouveau_util.h"
|
|
#include "swrast/swrast.h"
|
#include "tnl/tnl.h"
|
#include "util/bitscan.h"
|
#include "main/framebuffer.h"
|
|
static void
|
nouveau_alpha_func(struct gl_context *ctx, GLenum func, GLfloat ref)
|
{
|
context_dirty(ctx, ALPHA_FUNC);
|
}
|
|
static void
|
nouveau_blend_color(struct gl_context *ctx, const GLfloat color[4])
|
{
|
context_dirty(ctx, BLEND_COLOR);
|
}
|
|
static void
|
nouveau_blend_equation_separate(struct gl_context *ctx, GLenum modeRGB, GLenum modeA)
|
{
|
context_dirty(ctx, BLEND_EQUATION);
|
}
|
|
static void
|
nouveau_blend_func_separate(struct gl_context *ctx, GLenum sfactorRGB,
|
GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA)
|
{
|
context_dirty(ctx, BLEND_FUNC);
|
}
|
|
static void
|
nouveau_clip_plane(struct gl_context *ctx, GLenum plane, const GLfloat *equation)
|
{
|
context_dirty_i(ctx, CLIP_PLANE, plane - GL_CLIP_PLANE0);
|
}
|
|
static void
|
nouveau_color_mask(struct gl_context *ctx, GLboolean rmask, GLboolean gmask,
|
GLboolean bmask, GLboolean amask)
|
{
|
context_dirty(ctx, COLOR_MASK);
|
}
|
|
static void
|
nouveau_color_material(struct gl_context *ctx, GLenum face, GLenum mode)
|
{
|
context_dirty(ctx, COLOR_MATERIAL);
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
}
|
|
static void
|
nouveau_cull_face(struct gl_context *ctx, GLenum mode)
|
{
|
context_dirty(ctx, CULL_FACE);
|
}
|
|
static void
|
nouveau_front_face(struct gl_context *ctx, GLenum mode)
|
{
|
context_dirty(ctx, FRONT_FACE);
|
}
|
|
static void
|
nouveau_depth_func(struct gl_context *ctx, GLenum func)
|
{
|
context_dirty(ctx, DEPTH);
|
}
|
|
static void
|
nouveau_depth_mask(struct gl_context *ctx, GLboolean flag)
|
{
|
context_dirty(ctx, DEPTH);
|
}
|
|
static void
|
nouveau_read_buffer(struct gl_context *ctx, GLenum buffer)
|
{
|
nouveau_validate_framebuffer(ctx);
|
}
|
|
static void
|
nouveau_draw_buffers(struct gl_context *ctx, GLsizei n, const GLenum *buffers)
|
{
|
nouveau_validate_framebuffer(ctx);
|
context_dirty(ctx, FRAMEBUFFER);
|
}
|
|
static void
|
nouveau_enable(struct gl_context *ctx, GLenum cap, GLboolean state)
|
{
|
GLbitfield mask;
|
|
switch (cap) {
|
case GL_ALPHA_TEST:
|
context_dirty(ctx, ALPHA_FUNC);
|
break;
|
case GL_BLEND:
|
context_dirty(ctx, BLEND_EQUATION);
|
break;
|
case GL_COLOR_LOGIC_OP:
|
context_dirty(ctx, LOGIC_OPCODE);
|
break;
|
case GL_COLOR_MATERIAL:
|
context_dirty(ctx, COLOR_MATERIAL);
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
break;
|
case GL_COLOR_SUM_EXT:
|
context_dirty(ctx, FRAG);
|
context_dirty(ctx, LIGHT_MODEL);
|
break;
|
case GL_CULL_FACE:
|
context_dirty(ctx, CULL_FACE);
|
break;
|
case GL_DEPTH_TEST:
|
context_dirty(ctx, DEPTH);
|
break;
|
case GL_DITHER:
|
context_dirty(ctx, DITHER);
|
break;
|
case GL_FOG:
|
context_dirty(ctx, FOG);
|
context_dirty(ctx, FRAG);
|
context_dirty(ctx, MODELVIEW);
|
break;
|
case GL_LIGHT0:
|
case GL_LIGHT1:
|
case GL_LIGHT2:
|
case GL_LIGHT3:
|
case GL_LIGHT4:
|
case GL_LIGHT5:
|
case GL_LIGHT6:
|
case GL_LIGHT7:
|
context_dirty(ctx, MODELVIEW);
|
context_dirty(ctx, LIGHT_ENABLE);
|
context_dirty_i(ctx, LIGHT_SOURCE, cap - GL_LIGHT0);
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
context_dirty(ctx, MATERIAL_FRONT_SHININESS);
|
context_dirty(ctx, MATERIAL_BACK_SHININESS);
|
break;
|
case GL_LIGHTING:
|
context_dirty(ctx, FRAG);
|
context_dirty(ctx, MODELVIEW);
|
context_dirty(ctx, LIGHT_MODEL);
|
context_dirty(ctx, LIGHT_ENABLE);
|
|
mask = ctx->Light._EnabledLights;
|
while (mask) {
|
const int i = u_bit_scan(&mask);
|
context_dirty_i(ctx, LIGHT_SOURCE, i);
|
}
|
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
context_dirty(ctx, MATERIAL_FRONT_SHININESS);
|
context_dirty(ctx, MATERIAL_BACK_SHININESS);
|
break;
|
case GL_LINE_SMOOTH:
|
context_dirty(ctx, LINE_MODE);
|
break;
|
case GL_NORMALIZE:
|
context_dirty(ctx, LIGHT_ENABLE);
|
break;
|
case GL_POINT_SMOOTH:
|
context_dirty(ctx, POINT_MODE);
|
break;
|
case GL_POLYGON_OFFSET_POINT:
|
case GL_POLYGON_OFFSET_LINE:
|
case GL_POLYGON_OFFSET_FILL:
|
context_dirty(ctx, POLYGON_OFFSET);
|
break;
|
case GL_POLYGON_SMOOTH:
|
context_dirty(ctx, POLYGON_MODE);
|
break;
|
case GL_SCISSOR_TEST:
|
context_dirty(ctx, SCISSOR);
|
break;
|
case GL_STENCIL_TEST:
|
context_dirty(ctx, STENCIL_FUNC);
|
break;
|
case GL_TEXTURE_1D:
|
case GL_TEXTURE_2D:
|
case GL_TEXTURE_3D:
|
case GL_TEXTURE_RECTANGLE:
|
context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
|
context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
|
break;
|
case GL_TEXTURE_GEN_S:
|
case GL_TEXTURE_GEN_T:
|
case GL_TEXTURE_GEN_R:
|
case GL_TEXTURE_GEN_Q:
|
context_dirty_i(ctx, TEX_GEN, ctx->Texture.CurrentUnit);
|
context_dirty(ctx, MODELVIEW);
|
break;
|
}
|
}
|
|
static void
|
nouveau_fog(struct gl_context *ctx, GLenum pname, const GLfloat *params)
|
{
|
context_dirty(ctx, FOG);
|
}
|
|
static void
|
nouveau_light(struct gl_context *ctx, GLenum light, GLenum pname, const GLfloat *params)
|
{
|
switch (pname) {
|
case GL_AMBIENT:
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
break;
|
case GL_DIFFUSE:
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
break;
|
case GL_SPECULAR:
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
break;
|
case GL_SPOT_CUTOFF:
|
case GL_POSITION:
|
context_dirty(ctx, MODELVIEW);
|
context_dirty(ctx, LIGHT_ENABLE);
|
context_dirty_i(ctx, LIGHT_SOURCE, light - GL_LIGHT0);
|
break;
|
default:
|
context_dirty_i(ctx, LIGHT_SOURCE, light - GL_LIGHT0);
|
break;
|
}
|
}
|
|
static void
|
nouveau_light_model(struct gl_context *ctx, GLenum pname, const GLfloat *params)
|
{
|
context_dirty(ctx, LIGHT_MODEL);
|
context_dirty(ctx, MODELVIEW);
|
}
|
|
static void
|
nouveau_line_stipple(struct gl_context *ctx, GLint factor, GLushort pattern )
|
{
|
context_dirty(ctx, LINE_STIPPLE);
|
}
|
|
static void
|
nouveau_line_width(struct gl_context *ctx, GLfloat width)
|
{
|
context_dirty(ctx, LINE_MODE);
|
}
|
|
static void
|
nouveau_logic_opcode(struct gl_context *ctx, GLenum opcode)
|
{
|
context_dirty(ctx, LOGIC_OPCODE);
|
}
|
|
static void
|
nouveau_point_parameter(struct gl_context *ctx, GLenum pname, const GLfloat *params)
|
{
|
context_dirty(ctx, POINT_PARAMETER);
|
}
|
|
static void
|
nouveau_point_size(struct gl_context *ctx, GLfloat size)
|
{
|
context_dirty(ctx, POINT_MODE);
|
}
|
|
static void
|
nouveau_polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode)
|
{
|
context_dirty(ctx, POLYGON_MODE);
|
}
|
|
static void
|
nouveau_polygon_offset(struct gl_context *ctx, GLfloat factor, GLfloat units, GLfloat clamp)
|
{
|
context_dirty(ctx, POLYGON_OFFSET);
|
}
|
|
static void
|
nouveau_polygon_stipple(struct gl_context *ctx, const GLubyte *mask)
|
{
|
context_dirty(ctx, POLYGON_STIPPLE);
|
}
|
|
static void
|
nouveau_render_mode(struct gl_context *ctx, GLenum mode)
|
{
|
context_dirty(ctx, RENDER_MODE);
|
}
|
|
static void
|
nouveau_shade_model(struct gl_context *ctx, GLenum mode)
|
{
|
context_dirty(ctx, SHADE_MODEL);
|
}
|
|
static void
|
nouveau_stencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func,
|
GLint ref, GLuint mask)
|
{
|
context_dirty(ctx, STENCIL_FUNC);
|
}
|
|
static void
|
nouveau_stencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask)
|
{
|
context_dirty(ctx, STENCIL_MASK);
|
}
|
|
static void
|
nouveau_stencil_op_separate(struct gl_context *ctx, GLenum face, GLenum fail,
|
GLenum zfail, GLenum zpass)
|
{
|
context_dirty(ctx, STENCIL_OP);
|
}
|
|
static void
|
nouveau_tex_gen(struct gl_context *ctx, GLenum coord, GLenum pname,
|
const GLfloat *params)
|
{
|
switch (pname) {
|
case GL_TEXTURE_GEN_MODE:
|
context_dirty_i(ctx, TEX_GEN, ctx->Texture.CurrentUnit);
|
context_dirty(ctx, MODELVIEW);
|
break;
|
default:
|
context_dirty_i(ctx, TEX_GEN, ctx->Texture.CurrentUnit);
|
break;
|
}
|
}
|
|
static void
|
nouveau_tex_env(struct gl_context *ctx, GLenum target, GLenum pname,
|
const GLfloat *param)
|
{
|
switch (target) {
|
case GL_TEXTURE_FILTER_CONTROL_EXT:
|
context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
|
break;
|
default:
|
context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
|
break;
|
}
|
}
|
|
static void
|
nouveau_tex_parameter(struct gl_context *ctx,
|
struct gl_texture_object *t, GLenum pname)
|
{
|
switch (pname) {
|
case GL_TEXTURE_MAG_FILTER:
|
case GL_TEXTURE_WRAP_S:
|
case GL_TEXTURE_WRAP_T:
|
case GL_TEXTURE_WRAP_R:
|
case GL_TEXTURE_MIN_LOD:
|
case GL_TEXTURE_MAX_LOD:
|
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
case GL_TEXTURE_LOD_BIAS:
|
context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
|
break;
|
|
case GL_TEXTURE_MIN_FILTER:
|
case GL_TEXTURE_BASE_LEVEL:
|
case GL_TEXTURE_MAX_LEVEL:
|
nouveau_texture_reallocate(ctx, t);
|
context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
|
break;
|
}
|
}
|
|
void
|
nouveau_emit_nothing(struct gl_context *ctx, int emit)
|
{
|
}
|
|
int
|
nouveau_next_dirty_state(struct gl_context *ctx)
|
{
|
struct nouveau_context *nctx = to_nouveau_context(ctx);
|
int i = BITSET_FFS(nctx->dirty) - 1;
|
|
if (i < 0 || i >= context_drv(ctx)->num_emit)
|
return -1;
|
|
return i;
|
}
|
|
void
|
nouveau_state_emit(struct gl_context *ctx)
|
{
|
struct nouveau_context *nctx = to_nouveau_context(ctx);
|
const struct nouveau_driver *drv = context_drv(ctx);
|
int i;
|
|
while ((i = nouveau_next_dirty_state(ctx)) >= 0) {
|
BITSET_CLEAR(nctx->dirty, i);
|
drv->emit[i](ctx, i);
|
}
|
|
BITSET_ZERO(nctx->dirty);
|
}
|
|
static void
|
nouveau_update_state(struct gl_context *ctx)
|
{
|
GLbitfield new_state = ctx->NewState;
|
int i;
|
|
if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
|
_mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
|
|
if (new_state & (_NEW_PROJECTION | _NEW_MODELVIEW))
|
context_dirty(ctx, PROJECTION);
|
|
if (new_state & _NEW_MODELVIEW)
|
context_dirty(ctx, MODELVIEW);
|
|
if (new_state & _NEW_TEXTURE_MATRIX) {
|
for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++)
|
context_dirty_i(ctx, TEX_MAT, i);
|
}
|
|
if (new_state & _NEW_SCISSOR)
|
context_dirty(ctx, SCISSOR);
|
|
if (new_state & _NEW_VIEWPORT)
|
context_dirty(ctx, VIEWPORT);
|
|
if (new_state & _NEW_CURRENT_ATTRIB &&
|
new_state & _NEW_LIGHT) {
|
context_dirty(ctx, MATERIAL_FRONT_AMBIENT);
|
context_dirty(ctx, MATERIAL_BACK_AMBIENT);
|
context_dirty(ctx, MATERIAL_FRONT_DIFFUSE);
|
context_dirty(ctx, MATERIAL_BACK_DIFFUSE);
|
context_dirty(ctx, MATERIAL_FRONT_SPECULAR);
|
context_dirty(ctx, MATERIAL_BACK_SPECULAR);
|
context_dirty(ctx, MATERIAL_FRONT_SHININESS);
|
context_dirty(ctx, MATERIAL_BACK_SHININESS);
|
}
|
|
if (new_state & _NEW_TEXTURE) {
|
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
|
if (ctx->Texture.Unit[i].Sampler)
|
context_dirty_i(ctx, TEX_OBJ, i);
|
}
|
}
|
|
_swrast_InvalidateState(ctx, new_state);
|
_tnl_InvalidateState(ctx, new_state);
|
|
nouveau_state_emit(ctx);
|
}
|
|
void
|
nouveau_state_init(struct gl_context *ctx)
|
{
|
struct nouveau_context *nctx = to_nouveau_context(ctx);
|
|
ctx->Driver.AlphaFunc = nouveau_alpha_func;
|
ctx->Driver.BlendColor = nouveau_blend_color;
|
ctx->Driver.BlendEquationSeparate = nouveau_blend_equation_separate;
|
ctx->Driver.BlendFuncSeparate = nouveau_blend_func_separate;
|
ctx->Driver.ClipPlane = nouveau_clip_plane;
|
ctx->Driver.ColorMask = nouveau_color_mask;
|
ctx->Driver.ColorMaterial = nouveau_color_material;
|
ctx->Driver.CullFace = nouveau_cull_face;
|
ctx->Driver.FrontFace = nouveau_front_face;
|
ctx->Driver.DepthFunc = nouveau_depth_func;
|
ctx->Driver.DepthMask = nouveau_depth_mask;
|
ctx->Driver.ReadBuffer = nouveau_read_buffer;
|
ctx->Driver.DrawBuffers = nouveau_draw_buffers;
|
ctx->Driver.Enable = nouveau_enable;
|
ctx->Driver.Fogfv = nouveau_fog;
|
ctx->Driver.Lightfv = nouveau_light;
|
ctx->Driver.LightModelfv = nouveau_light_model;
|
ctx->Driver.LineStipple = nouveau_line_stipple;
|
ctx->Driver.LineWidth = nouveau_line_width;
|
ctx->Driver.LogicOpcode = nouveau_logic_opcode;
|
ctx->Driver.PointParameterfv = nouveau_point_parameter;
|
ctx->Driver.PointSize = nouveau_point_size;
|
ctx->Driver.PolygonMode = nouveau_polygon_mode;
|
ctx->Driver.PolygonOffset = nouveau_polygon_offset;
|
ctx->Driver.PolygonStipple = nouveau_polygon_stipple;
|
ctx->Driver.RenderMode = nouveau_render_mode;
|
ctx->Driver.ShadeModel = nouveau_shade_model;
|
ctx->Driver.StencilFuncSeparate = nouveau_stencil_func_separate;
|
ctx->Driver.StencilMaskSeparate = nouveau_stencil_mask_separate;
|
ctx->Driver.StencilOpSeparate = nouveau_stencil_op_separate;
|
ctx->Driver.TexGen = nouveau_tex_gen;
|
ctx->Driver.TexEnv = nouveau_tex_env;
|
ctx->Driver.TexParameter = nouveau_tex_parameter;
|
|
ctx->Driver.UpdateState = nouveau_update_state;
|
|
BITSET_ONES(nctx->dirty);
|
}
|