#include #include #include #include #include #include #include #include "swblend.h" static int present(int px, int py, struct sw_blend_buffer *buf, int dx, int dy, int *bx, int *by) { if(px >= dx && px < (dx + buf->width) && py >= dy && py < (dy + buf->height)) { *bx = px - dx; *by = py - dy; return 1; } return 0; } #define min(x,y) (x < y ? x : y) static int blend(uint32_t src, uint32_t dst, uint32_t *res, uint32_t blendfuncs) { float fr, fg, fb, fa; float sr = ((src & 0x00ff0000) >> 16)/255.0; float sg = ((src & 0x0000ff00) >> 8)/255.0; float sb = ((src & 0x000000ff) >> 0)/255.0; float sa = ((src & 0xff000000) >> 24)/255.0; float dr = ((dst & 0x00ff0000) >> 16)/255.0; float dg = ((dst & 0x0000ff00) >> 8)/255.0; float db = ((dst & 0x000000ff) >> 0)/255.0; float da = ((dst & 0xff000000) >> 24)/255.0; switch(blendfuncs) { case SRC_GL_SRC_ALPHA | DST_GL_ONE_MINUS_SRC_ALPHA: fr = min(1.0, sa*sr + (1-sa)*dr); fg = min(1.0, sa*sg + (1-sa)*dg); fb = min(1.0, sa*sb + (1-sa)*db); fa = min(1.0, sa*sa + (1-sa)*da); break; default: printf("unsupported blend functions\n"); return -1; } *res = ((((uint32_t)(fr * 255)) & 0xff) << 16) | ((((uint32_t)(fg * 255)) & 0xff) << 8) | ((((uint32_t)(fb * 255)) & 0xff) << 0) | ((((uint32_t)(fa * 255)) & 0xff) << 24); return 0; } static int read_buf_pixel(struct sw_blend_buffer *buf, int x, int y, uint32_t *color) { switch(buf->format) { case DRM_FORMAT_ARGB8888: *color = *((uint32_t *)(((uint8_t *)buf->vaddr) + (buf->stride * y) + (x * 4))); break; case DRM_FORMAT_XRGB8888: *color = *((uint32_t *)(((uint8_t *)buf->vaddr) + (buf->stride * y) + (x * 4))); *color = ((*color & 0x00ffffff) | 0xff000000); break; default: printf("unsupported format\n"); return -1; } return 0; } static int write_buf_pixel(struct sw_blend_buffer *buf, int x, int y, uint32_t color) { switch(buf->format) { case DRM_FORMAT_ARGB8888: *((uint32_t *)(((uint8_t *)buf->vaddr) + (buf->stride * y) + (x * 4))) = color; break; case DRM_FORMAT_XRGB8888: *((uint32_t *)(((uint8_t *)buf->vaddr) + (buf->stride * y) + (x * 4))) = ((color & 0x00ffffff) | 0xff000000); break; default: printf("unsupported format\n"); return -1; } return 0; } int sw_blend(struct sw_blend_buffer *dst_buf, struct sw_blend_layer *layers, uint32_t layer_cnt, bool clear, uint32_t clear_color, struct rect *past_damages, int past_dcount, struct rect *damages, int dcount) { int i, d; int px, py; uint32_t dstcolor, srccolor; int ret; if(!clear) goto nopastclear; for(d = 0; d < past_dcount; d++) { struct rect *r = &past_damages[d]; for(py = r->top; py < r->top + r->height; py++) { for(px = r->left; px < r->left + r->width; px++) { write_buf_pixel(dst_buf, px, py, clear_color); } } } nopastclear: for(d = 0; d < dcount; d++) { struct rect *r = &damages[d]; for(py = r->top; py < r->top + r->height; py++) { for(px = r->left; px < r->left + r->width; px++) { if(clear) dstcolor = clear_color; else { ret = read_buf_pixel(dst_buf, px, py, &dstcolor); if(ret) { printf("reading pixel from dst buffer (%ux%u) failed\n", px, py); return -1; } } for(i = 0; i < layer_cnt; i++) { int bx, by; if(present(px, py, &layers[i].buf, layers[i].x, layers[i].y, &bx, &by)) { ret = read_buf_pixel(&layers[i].buf, bx, by, &srccolor); if(ret) { printf("reading pixel from src buffer (%ux%u) failed\n", bx, by); return -1; } if(layers[i].blend) { uint32_t rescolor; ret = blend(srccolor, dstcolor, &rescolor, layers[i].blendfuncs); if(ret) { printf("blend failed for layer %u at dst (%ux%u) failed\n", i, px, py); return -1; } else dstcolor = rescolor; } else dstcolor = srccolor; } } ret = write_buf_pixel(dst_buf, px, py, dstcolor); if(ret) { printf("writing pixel to dst buffer (%ux%u) failed\n", px, py); return -1; } } } } return 0; }