/* * 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); }