diff --git a/glamor/glamor.c b/glamor/glamor.c index 86a76940e..050dd3d66 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -97,12 +97,21 @@ glamor_init(ScreenPtr screen) dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, glamor_priv); + glewInit(); + + if (!GLEW_ARB_shader_objects) { + ErrorF("GL_ARB_shader_objects required\n"); + goto fail; + } + if (!GLEW_ARB_vertex_shader) { + ErrorF("GL_ARB_vertex_shader required\n"); + goto fail; + } + if (!RegisterBlockAndWakeupHandlers(glamor_block_handler, glamor_wakeup_handler, NULL)) { - dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, NULL); - xfree(glamor_priv); - return FALSE; + goto fail; } glamor_priv->saved_create_gc = screen->CreateGC; @@ -114,9 +123,14 @@ glamor_init(ScreenPtr screen) glamor_priv->saved_destroy_pixmap = screen->DestroyPixmap; screen->DestroyPixmap = glamor_destroy_pixmap; - glewInit(); + glamor_init_solid_shader(screen); return TRUE; + +fail: + xfree(glamor_priv); + dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, NULL); + return FALSE; } void diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index 7f97190cc..9c892ead9 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -39,16 +39,7 @@ #include "glamor_priv.h" -static void -glamor_set_color_from_fgpixel(PixmapPtr pixmap, unsigned long fg_pixel) -{ - glColor4ub((fg_pixel >> 16) & 0xff, - (fg_pixel >> 8) & 0xff, - (fg_pixel) & 0xff, - (fg_pixel >> 24) & 0xff); -} - -static Bool +Bool glamor_set_destination_pixmap(PixmapPtr pixmap) { ScreenPtr screen = pixmap->drawable.pScreen; @@ -63,37 +54,103 @@ glamor_set_destination_pixmap(PixmapPtr pixmap) screen_pixmap->drawable.width, screen_pixmap->drawable.height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, screen_pixmap->drawable.width, - 0, screen_pixmap->drawable.height, - -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - return TRUE; } void -glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, - unsigned char alu, unsigned long planemask, unsigned long fg_pixel) +glamor_get_transform_uniform_locations(GLint prog, + glamor_transform_uniforms *uniform_locations) { - int x1 = x; - int x2 = x + width; - int y1 = y; - int y2 = y + height; + uniform_locations->x_bias = glGetUniformLocationARB(prog, "x_bias"); + uniform_locations->x_scale = glGetUniformLocationARB(prog, "x_scale"); + uniform_locations->y_bias = glGetUniformLocationARB(prog, "y_bias"); + uniform_locations->y_scale = glGetUniformLocationARB(prog, "y_scale"); +} - if (!glamor_set_destination_pixmap(pixmap)) - return; - glamor_set_color_from_fgpixel(pixmap, fg_pixel); +/* We don't use a full matrix for our transformations because it's + * wasteful when all we want is to rescale to NDC and possibly do a flip + * if it's the front buffer. + */ +void +glamor_set_transform_for_pixmap(PixmapPtr pixmap, + glamor_transform_uniforms *uniform_locations) +{ + glUniform1fARB(uniform_locations->x_bias, -pixmap->drawable.width / 2.0f); + glUniform1fARB(uniform_locations->x_scale, 2.0f / pixmap->drawable.width); + glUniform1fARB(uniform_locations->y_bias, -pixmap->drawable.height / 2.0f); + glUniform1fARB(uniform_locations->y_scale, -2.0f / pixmap->drawable.height); +} - glBegin(GL_TRIANGLE_FAN); - glVertex2f(x1, y1); - glVertex2f(x1, y2); - glVertex2f(x2, y2); - glVertex2f(x2, y1); - glEnd(); +GLint +glamor_compile_glsl_prog(GLenum type, const char *source) +{ + GLint ok; + GLint prog; + + prog = glCreateShaderObjectARB(type); + glShaderSourceARB(prog, 1, (const GLchar **)&source, NULL); + glCompileShaderARB(prog); + glGetObjectParameterivARB(prog, GL_OBJECT_COMPILE_STATUS_ARB, &ok); + if (!ok) { + GLchar *info; + GLint size; + + glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &size); + info = malloc(size); + + glGetInfoLogARB(prog, size, NULL, info); + ErrorF("Failed to compile %s: %s\n", + type == GL_FRAGMENT_SHADER ? "FS" : "VS", + info); + ErrorF("Program source:\n%s", source); + FatalError("GLSL compile failure\n"); + } + + return prog; +} + +void +glamor_link_glsl_prog(GLint prog) +{ + GLint ok; + + glLinkProgram(prog); + glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &ok); + if (!ok) { + GLchar *info; + GLint size; + + glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &size); + info = malloc(size); + + glGetInfoLogARB(prog, size, NULL, info); + ErrorF("Failed to link: %s\n", + info); + FatalError("GLSL link failure\n"); + } +} + +static float ubyte_to_float(uint8_t b) +{ + return b / 255.0f; +} + +void +glamor_get_color_4f_from_pixel(PixmapPtr pixmap, unsigned long fg_pixel, + GLfloat *color) +{ + if (pixmap->drawable.depth < 24) { + ErrorF("pixmap with bad depth\n"); + color[0] = 1.0; + color[1] = 0.0; + color[2] = 1.0; + color[3] = 1.0; + } else { + color[0] = ubyte_to_float(fg_pixel >> 16); + color[1] = ubyte_to_float(fg_pixel >> 8); + color[2] = ubyte_to_float(fg_pixel >> 0); + color[3] = ubyte_to_float(fg_pixel >> 24); + } } void diff --git a/glamor/glamor_fill.c b/glamor/glamor_fill.c index 36e7badfb..0d87bd037 100644 --- a/glamor/glamor_fill.c +++ b/glamor/glamor_fill.c @@ -82,3 +82,89 @@ glamor_fill(DrawablePtr drawable, break; } } + +void +glamor_init_solid_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + const char *solid_vs_only = + "uniform vec4 color;\n" + "uniform float x_bias;\n" + "uniform float x_scale;\n" + "uniform float y_bias;\n" + "uniform float y_scale;\n" + "void main()\n" + "{\n" + " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n" + " (gl_Vertex.y + y_bias) * y_scale,\n" + " 0,\n" + " 1);\n" + " gl_Color = color;\n" + "}\n"; + const char *solid_vs = + "uniform float x_bias;\n" + "uniform float x_scale;\n" + "uniform float y_bias;\n" + "uniform float y_scale;\n" + "void main()\n" + "{\n" + " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n" + " (gl_Vertex.y + y_bias) * y_scale,\n" + " 0,\n" + " 1);\n" + "}\n"; + const char *solid_fs = + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color;\n" + "}\n"; + GLint fs_prog, vs_prog; + + glamor_priv->solid_prog = glCreateProgramObjectARB(); + if (GLEW_ARB_fragment_shader) { + vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, solid_vs); + fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, solid_fs); + glAttachObjectARB(glamor_priv->solid_prog, vs_prog); + glAttachObjectARB(glamor_priv->solid_prog, fs_prog); + } else { + vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, solid_vs_only); + glAttachObjectARB(glamor_priv->solid_prog, vs_prog); + } + glamor_link_glsl_prog(glamor_priv->solid_prog); + + glamor_priv->solid_color_uniform_location = + glGetUniformLocationARB(glamor_priv->solid_prog, "color"); + glamor_get_transform_uniform_locations(glamor_priv->solid_prog, + &glamor_priv->solid_transform); +} + +void +glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, + unsigned char alu, unsigned long planemask, unsigned long fg_pixel) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + int x1 = x; + int x2 = x + width; + int y1 = y; + int y2 = y + height; + GLfloat color[4]; + + if (!glamor_set_destination_pixmap(pixmap)) + return; + + glUseProgramObjectARB(glamor_priv->solid_prog); + glamor_get_color_4f_from_pixel(pixmap, fg_pixel, color); + glUniform4fvARB(glamor_priv->solid_color_uniform_location, 1, color); + glamor_set_transform_for_pixmap(pixmap, &glamor_priv->solid_transform); + + glBegin(GL_TRIANGLE_FAN); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + glEnd(); + + glUseProgramObjectARB(0); +} diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 285799da5..3216a7a4a 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -31,10 +31,22 @@ #include "glamor.h" #include +typedef struct glamor_transform_uniforms { + GLint x_bias; + GLint x_scale; + GLint y_bias; + GLint y_scale; +} glamor_transform_uniforms; + typedef struct glamor_screen_private { CreateGCProcPtr saved_create_gc; CreatePixmapProcPtr saved_create_pixmap; DestroyPixmapProcPtr saved_destroy_pixmap; + + /* glamor_solid */ + GLint solid_prog; + GLint solid_color_uniform_location; + glamor_transform_uniforms solid_transform; } glamor_screen_private; extern DevPrivateKey glamor_screen_private_key; @@ -50,9 +62,6 @@ PixmapPtr glamor_get_drawable_pixmap(DrawablePtr drawable); /* glamor_core.c */ Bool glamor_create_gc(GCPtr gc); -void glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, - unsigned char alu, unsigned long planemask, - unsigned long fg_pixel); void glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple, int x, int y, int width, int height, unsigned char alu, unsigned long planemask, @@ -62,6 +71,15 @@ void glamor_tile(PixmapPtr pixmap, PixmapPtr tile, int x, int y, int width, int height, unsigned char alu, unsigned long planemask, int tile_x, int tile_y); +GLint glamor_compile_glsl_prog(GLenum type, const char *source); +void glamor_link_glsl_prog(GLint prog); +void glamor_get_color_4f_from_pixel(PixmapPtr pixmap, unsigned long fg_pixel, + GLfloat *color); +Bool glamor_set_destination_pixmap(PixmapPtr pixmap); +void glamor_get_transform_uniform_locations(GLint prog, + glamor_transform_uniforms *uniform_locations); +void glamor_set_transform_for_pixmap(PixmapPtr pixmap, + glamor_transform_uniforms *uniform_locations); /* glamor_fill.c */ void glamor_fill(DrawablePtr drawable, @@ -70,6 +88,9 @@ void glamor_fill(DrawablePtr drawable, int y, int width, int height); +void glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, + unsigned char alu, unsigned long planemask, + unsigned long fg_pixel); /* glamor_fillspans.c */ void glamor_fill_spans(DrawablePtr drawable, @@ -79,4 +100,6 @@ void glamor_fill_spans(DrawablePtr drawable, int *widths, int sorted); +void glamor_init_solid_shader(ScreenPtr screen); + #endif /* GLAMOR_PRIV_H */