glamor_compositerects: Implement optimized version.

Don't call miCompositeRects. Use glamor_composite_clipped_region
to render those boxes at once.
Also add a new function glamor_solid_boxes to fill boxes at once.

Signed-off-by: Zhigang Gong <zhigang.gong@linux.intel.com>
This commit is contained in:
Zhigang Gong 2012-06-27 12:53:40 +08:00 committed by Eric Anholt
parent dd79243398
commit 4d1a2173f2
6 changed files with 439 additions and 49 deletions

View File

@ -48,6 +48,7 @@ libglamor_la_SOURCES = \
glamor_window.c\
glamor_gl_dispatch.c\
glamor_fbo.c\
glamor_compositerects.c\
glamor.h
sdk_HEADERS = glamor.h

View File

@ -383,6 +383,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
glamor_priv->saved_procs.composite = ps->Composite;
ps->Composite = glamor_composite;
glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
ps->Trapezoids = glamor_trapezoids;
@ -395,6 +396,9 @@ glamor_init(ScreenPtr screen, unsigned int flags)
}
glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
ps->CompositeRects = glamor_composite_rectangles;
glamor_priv->saved_procs.glyphs = ps->Glyphs;
ps->Glyphs = glamor_glyphs;
@ -510,10 +514,12 @@ glamor_close_screen(int idx, ScreenPtr screen)
ps->Composite = glamor_priv->saved_procs.composite;
ps->Trapezoids = glamor_priv->saved_procs.trapezoids;
ps->Glyphs = glamor_priv->saved_procs.glyphs;
ps->Triangles = glamor_priv->saved_procs.triangles;
ps->CreatePicture = glamor_priv->saved_procs.create_picture;
}
ps->CompositeRects = glamor_priv->saved_procs.composite_rects;
ps->Glyphs = glamor_priv->saved_procs.glyphs;
ps->UnrealizeGlyph = glamor_priv->saved_procs.unrealize_glyph;
#endif
screen_pixmap = screen->GetScreenPixmap(screen);
glamor_set_pixmap_private(screen_pixmap, NULL);

View File

@ -0,0 +1,278 @@
/*
* Copyright © 2009 Intel Corporation
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Zhigang Gong <zhigang.gong@linux.intel.com>
*
* original author is Chris Wilson at sna.
*
*/
#include "glamor_priv.h"
#include "mipict.h"
#include "damage.h"
/** @file glamor_compositerects.
*
* compositeRects acceleration implementation
*/
static int16_t bound(int16_t a, uint16_t b)
{
int v = (int)a + (int)b;
if (v > MAXSHORT)
return MAXSHORT;
return v;
}
static Bool
_pixman_region_init_clipped_rectangles(pixman_region16_t *region,
unsigned int num_rects,
xRectangle *rects,
int tx, int ty,
BoxPtr extents)
{
pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
pixman_bool_t ret;
unsigned int i, j;
if (num_rects > ARRAY_SIZE(stack_boxes)) {
boxes = malloc(sizeof(pixman_box16_t) * num_rects);
if (boxes == NULL)
return FALSE;
}
for (i = j = 0; i < num_rects; i++) {
boxes[j].x1 = rects[i].x + tx;
if (boxes[j].x1 < extents->x1)
boxes[j].x1 = extents->x1;
boxes[j].y1 = rects[i].y + ty;
if (boxes[j].y1 < extents->y1)
boxes[j].y1 = extents->y1;
boxes[j].x2 = bound(rects[i].x + tx, rects[i].width);
if (boxes[j].x2 > extents->x2)
boxes[j].x2 = extents->x2;
boxes[j].y2 = bound(rects[i].y + ty, rects[i].height);
if (boxes[j].y2 > extents->y2)
boxes[j].y2 = extents->y2;
if (boxes[j].x2 > boxes[j].x1 && boxes[j].y2 > boxes[j].y1)
j++;
}
ret = FALSE;
if (j)
ret = pixman_region_init_rects(region, boxes, j);
if (boxes != stack_boxes)
free(boxes);
DEBUGF("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n",
__FUNCTION__, num_rects,
region->extents.x1, region->extents.y1,
region->extents.x2, region->extents.y2,
j);
return ret;
}
void
glamor_composite_rectangles(CARD8 op,
PicturePtr dst,
xRenderColor *color,
int num_rects,
xRectangle *rects)
{
PixmapPtr pixmap;
struct glamor_pixmap_private *priv;
pixman_region16_t region;
pixman_box16_t *boxes;
int dst_x, dst_y;
int num_boxes;
PicturePtr source = NULL;
Bool need_free_region = FALSE;
DEBUGF("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
__FUNCTION__, op,
(color->alpha >> 8 << 24) |
(color->red >> 8 << 16) |
(color->green >> 8 << 8) |
(color->blue >> 8 << 0),
num_rects,
rects[0].x, rects[0].y, rects[0].width, rects[0].height);
if (!num_rects)
return;
if (region_is_empty(dst->pCompositeClip)) {
DEBUGF("%s: empty clip, skipping\n", __FUNCTION__);
return;
}
pixmap = glamor_get_drawable_pixmap(dst->pDrawable);
priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
goto fallback;
if (dst->alphaMap) {
DEBUGF("%s: fallback, dst has an alpha-map\n", __FUNCTION__);
goto fallback;
}
if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) {
switch (op) {
case PictOpOver:
case PictOpOutReverse:
case PictOpAdd:
return;
case PictOpInReverse:
case PictOpSrc:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOut;
break;
case PictOpXor:
op = PictOpOverReverse;
break;
}
}
if (color->alpha <= 0x00ff) {
switch (op) {
case PictOpOver:
case PictOpOutReverse:
return;
case PictOpInReverse:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOut;
break;
case PictOpXor:
op = PictOpOverReverse;
break;
}
} else if (color->alpha >= 0xff00) {
switch (op) {
case PictOpOver:
op = PictOpSrc;
break;
case PictOpInReverse:
return;
case PictOpOutReverse:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOverReverse;
break;
case PictOpXor:
op = PictOpOut;
break;
}
}
DEBUGF("%s: converted to op %d\n", __FUNCTION__, op);
if (!_pixman_region_init_clipped_rectangles(&region,
num_rects, rects,
dst->pDrawable->x,
dst->pDrawable->y,
&dst->pCompositeClip->extents))
{
DEBUGF("%s: allocation failed for region\n", __FUNCTION__);
return;
}
need_free_region = TRUE;
DEBUGF("%s: drawable extents (%d, %d),(%d, %d) x %d\n",
__FUNCTION__,
RegionExtents(&region)->x1, RegionExtents(&region)->y1,
RegionExtents(&region)->x2, RegionExtents(&region)->y2,
RegionNumRects(&region));
if (dst->pCompositeClip->data &&
(!pixman_region_intersect(&region, &region, dst->pCompositeClip) ||
region_is_empty(&region))) {
DEBUGF(("%s: zero-intersection between rectangles and clip\n",
__FUNCTION__));
pixman_region_fini(&region);
return;
}
DEBUGF("%s: clipped extents (%d, %d),(%d, %d) x %d\n",
__FUNCTION__,
RegionExtents(&region)->x1, RegionExtents(&region)->y1,
RegionExtents(&region)->x2, RegionExtents(&region)->y2,
RegionNumRects(&region));
glamor_get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y);
pixman_region_translate(&region, dst_x, dst_y);
DEBUGF("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n",
__FUNCTION__, dst_x, dst_y,
RegionExtents(&region)->x1, RegionExtents(&region)->y1,
RegionExtents(&region)->x2, RegionExtents(&region)->y2);
boxes = pixman_region_rectangles(&region, &num_boxes);
if (op == PictOpSrc || op == PictOpClear) {
CARD32 pixel;
if (op == PictOpClear)
pixel = 0;
else
miRenderColorToPixel(dst->pFormat, color, &pixel);
glamor_solid_boxes(pixmap, boxes, num_boxes, pixel);
goto done;
} else {
if (likely(priv->type != GLAMOR_TEXTURE_LARGE)) {
int error;
source = CreateSolidPicture(0, color, &error);
if (!source)
goto done;
if (glamor_composite_clipped_region(op, source,
NULL, dst,
NULL, NULL, priv,
&region,
0,0,0,0,0,0))
goto done;
}
}
fallback:
miCompositeRects(op, dst, color, num_rects, rects);
done:
/* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
* manually append the damaged regions ourselves.
*/
DamageRegionAppend(&pixmap->drawable, &region);
DamageRegionProcessPending(&pixmap->drawable);
if (need_free_region)
pixman_region_fini(&region);
if (source)
FreePicture(source, 0);
return;
}

View File

@ -180,6 +180,87 @@ glamor_fini_solid_shader(ScreenPtr screen)
glamor_put_dispatch(glamor_priv);
}
static void
_glamor_solid_boxes(PixmapPtr pixmap, BoxPtr box, int nbox, float *color)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv =
glamor_get_screen_private(screen);
glamor_pixmap_private *pixmap_priv =
glamor_get_pixmap_private(pixmap);
glamor_gl_dispatch *dispatch;
GLfloat xscale, yscale;
float vertices[32];
float *pvertices = vertices;
int valid_nbox = ARRAY_SIZE(vertices);
glamor_set_destination_pixmap_priv_nc(pixmap_priv);
dispatch = glamor_get_dispatch(glamor_priv);
dispatch->glUseProgram(glamor_priv->solid_prog);
dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
1, color);
pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
if (unlikely(nbox*4*2 > ARRAY_SIZE(vertices))) {
int allocated_box;
if (nbox * 6 > GLAMOR_COMPOSITE_VBO_VERT_CNT) {
allocated_box = GLAMOR_COMPOSITE_VBO_VERT_CNT / 6;
} else
allocated_box = nbox;
pvertices = malloc(allocated_box * 4 * 2 * sizeof(float));
if (pvertices)
valid_nbox = allocated_box;
else {
pvertices = vertices;
valid_nbox = ARRAY_SIZE(vertices) / (4*2);
}
}
#define GLAMOR_COMPOSITE_VBO_VERT_CNT 1024
if (unlikely(nbox > 1))
dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof(float),
pvertices);
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
while(nbox) {
int box_cnt, i;
float *valid_vertices;
valid_vertices = pvertices;
box_cnt = nbox > valid_nbox ? valid_nbox : nbox;
for (i = 0; i < box_cnt; i++) {
glamor_set_normalize_vcoords(pixmap_priv, xscale, yscale,
box[i].x1, box[i].y1,
box[i].x2, box[i].y2,
glamor_priv->yInverted,
valid_vertices);
valid_vertices += 4*2;
}
if (box_cnt == 1)
dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, box_cnt * 4);
else
dispatch->glDrawElements(GL_TRIANGLES,
box_cnt * 6,
GL_UNSIGNED_SHORT,
NULL);
nbox -= box_cnt;
box += box_cnt;
}
if (pvertices != vertices)
free(pvertices);
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
dispatch->glUseProgram(0);
glamor_put_dispatch(glamor_priv);
}
static void
_glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
float *color)
@ -221,6 +302,52 @@ _glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
glamor_put_dispatch(glamor_priv);
}
Bool
glamor_solid_boxes(PixmapPtr pixmap,
BoxPtr box, int nbox,
unsigned long fg_pixel)
{
glamor_pixmap_private *pixmap_priv;
GLfloat color[4];
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return FALSE;
glamor_get_rgba_from_pixel(fg_pixel,
&color[0],
&color[1],
&color[2],
&color[3], format_for_pixmap(pixmap));
if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
RegionRec region;
int n_region;
glamor_pixmap_clipped_regions *clipped_regions;
int i;
RegionInitBoxes(&region, box, nbox);
clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
for(i = 0; i < n_region; i++)
{
BoxPtr inner_box;
int inner_nbox;
SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
inner_box = RegionRects(clipped_regions[i].region);
inner_nbox = RegionNumRects(clipped_regions[i].region);
_glamor_solid_boxes(pixmap, inner_box, inner_nbox, color);
RegionDestroy(clipped_regions[i].region);
}
free(clipped_regions);
RegionUninit(&region);
} else
_glamor_solid_boxes(pixmap, box, nbox, color);
return TRUE;
}
Bool
glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
unsigned char alu, unsigned long planemask,
@ -231,7 +358,7 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
glamor_get_screen_private(screen);
glamor_pixmap_private *pixmap_priv;
glamor_gl_dispatch *dispatch;
GLfloat color[4];
BoxRec box;
pixmap_priv = glamor_get_pixmap_private(pixmap);
@ -244,63 +371,25 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
return FALSE;
}
glamor_get_rgba_from_pixel(fg_pixel,
&color[0],
&color[1],
&color[2],
&color[3], format_for_pixmap(pixmap));
dispatch = glamor_get_dispatch(glamor_priv);
if (!glamor_set_alu(dispatch, alu)) {
if (alu == GXclear)
color[0] = color[1] = color[2] = color[3] = 0.0;
fg_pixel = 0;
else {
glamor_fallback("unsupported alu %x\n", alu);
glamor_put_dispatch(glamor_priv);
return FALSE;
}
}
if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
RegionRec region;
BoxRec box;
int n_region;
glamor_pixmap_clipped_regions *clipped_regions;
int i,j;
box.x1 = x;
box.y1 = y;
box.x2 = x + width;
box.y2 = y + height;
RegionInitBoxes(&region, &box, 1);
clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
for(i = 0; i < n_region; i++)
{
BoxPtr boxes;
int nbox;
SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
boxes = RegionRects(clipped_regions[i].region);
nbox = RegionNumRects(clipped_regions[i].region);
for(j = 0; j < nbox; j++)
{
_glamor_solid(pixmap, boxes[j].x1, boxes[j].y1,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1, color);
}
RegionDestroy(clipped_regions[i].region);
}
free(clipped_regions);
RegionUninit(&region);
} else
_glamor_solid(pixmap,
x,
y,
width, height,
color);
box.x1 = x;
box.y1 = y;
box.x2 = x + width;
box.y2 = y + height;
glamor_solid_boxes(pixmap, &box, 1, fg_pixel);
glamor_set_alu(dispatch, GXcopy);
glamor_put_dispatch(glamor_priv);
return TRUE;
}

View File

@ -210,6 +210,7 @@ struct glamor_saved_procs {
GetSpansProcPtr get_spans;
GetImageProcPtr get_image;
CompositeProcPtr composite;
CompositeRectsProcPtr composite_rects;
TrapezoidsProcPtr trapezoids;
GlyphsProcPtr glyphs;
ChangeWindowAttributesProcPtr change_window_attributes;
@ -644,8 +645,10 @@ Bool glamor_fill(DrawablePtr drawable,
Bool glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
unsigned char alu, unsigned long planemask,
unsigned long fg_pixel);
void glamor_solid_fail_region(PixmapPtr pixmap,
int x, int y, int width, int height);
Bool
glamor_solid_boxes(PixmapPtr pixmap,
BoxPtr box, int nbox,
unsigned long fg_pixel);
/* glamor_fillspans.c */
void glamor_fill_spans(DrawablePtr drawable,
@ -988,6 +991,13 @@ void
glamor_poly_line(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr ppt);
void
glamor_composite_rectangles(CARD8 op,
PicturePtr dst,
xRenderColor *color,
int num_rects,
xRectangle *rects);
#include"glamor_utils.h"
/* Dynamic pixmap upload to texture if needed.

View File

@ -792,6 +792,12 @@ glamor_translate_boxes(BoxPtr boxes, int nbox, int dx, int dy)
}
}
static inline Bool
region_is_empty(pixman_region16_t *region)
{
return region->data && region->data->numRects == 0;
}
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
#define MIN(a,b) ((a) < (b) ? (a) : (b))