1 /* 2 ** 3 ** Copyright 2009, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include <stdlib.h> 19 #include <stdio.h> 20 21 #include "context.h" 22 #include "fp.h" 23 #include "state.h" 24 #include "matrix.h" 25 #include "vertex.h" 26 #include "light.h" 27 #include "primitives.h" 28 #include "texture.h" 29 #include "BufferObjectManager.h" 30 #include "TextureObjectManager.h" 31 32 #include <hardware/gralloc.h> 33 #include <hardware/copybit.h> 34 #include <private/ui/android_natives_priv.h> 35 36 #include <ui/GraphicBuffer.h> 37 #include <ui/Region.h> 38 #include <ui/Rect.h> 39 40 41 #define DEBUG_COPYBIT false 42 43 // ---------------------------------------------------------------------------- 44 45 namespace android { 46 47 static void textureToCopyBitImage( 48 const GGLSurface* surface, int32_t opFormat, 49 android_native_buffer_t* buffer, copybit_image_t* img) 50 { 51 img->w = surface->stride; 52 img->h = surface->height; 53 img->format = opFormat; 54 img->base = surface->data; 55 img->handle = (native_handle_t *)buffer->handle; 56 } 57 58 struct clipRectRegion : public copybit_region_t { 59 clipRectRegion(ogles_context_t* c) 60 { 61 scissor_t const* scissor = &c->rasterizer.state.scissor; 62 r.l = scissor->left; 63 r.t = scissor->top; 64 r.r = scissor->right; 65 r.b = scissor->bottom; 66 next = iterate; 67 } 68 private: 69 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { 70 *rect = static_cast<clipRectRegion const*>(self)->r; 71 const_cast<copybit_region_t *>(self)->next = iterate_done; 72 return 1; 73 } 74 static int iterate_done(copybit_region_t const *, copybit_rect_t*) { 75 return 0; 76 } 77 public: 78 copybit_rect_t r; 79 }; 80 81 static bool supportedCopybitsFormat(int format) { 82 switch (format) { 83 case COPYBIT_FORMAT_RGBA_8888: 84 case COPYBIT_FORMAT_RGBX_8888: 85 case COPYBIT_FORMAT_RGB_888: 86 case COPYBIT_FORMAT_RGB_565: 87 case COPYBIT_FORMAT_BGRA_8888: 88 case COPYBIT_FORMAT_RGBA_5551: 89 case COPYBIT_FORMAT_RGBA_4444: 90 return true; 91 default: 92 return false; 93 } 94 } 95 96 static bool hasAlpha(int format) { 97 switch (format) { 98 case COPYBIT_FORMAT_RGBA_8888: 99 case COPYBIT_FORMAT_BGRA_8888: 100 case COPYBIT_FORMAT_RGBA_5551: 101 case COPYBIT_FORMAT_RGBA_4444: 102 return true; 103 default: 104 return false; 105 } 106 } 107 108 static inline int fixedToByte(GGLfixed val) { 109 return (val - (val >> 8)) >> 8; 110 } 111 112 /** 113 * Performs a quick check of the rendering state. If this function returns 114 * false we cannot use the copybit driver. 115 */ 116 117 static bool checkContext(ogles_context_t* c) { 118 119 // By convention copybitQuickCheckContext() has already returned true. 120 // avoid checking the same information again. 121 122 if (c->copybits.blitEngine == NULL) { 123 LOGD_IF(DEBUG_COPYBIT, "no copybit hal"); 124 return false; 125 } 126 127 if (c->rasterizer.state.enables 128 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { 129 LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog"); 130 return false; 131 } 132 133 // Note: The drawSurfaceBuffer is only set for destination 134 // surfaces types that are supported by the hardware and 135 // do not have an alpha channel. So we don't have to re-check that here. 136 137 static const int tmu = 0; 138 texture_unit_t& u(c->textures.tmu[tmu]); 139 EGLTextureObject* textureObject = u.texture; 140 141 if (!supportedCopybitsFormat(textureObject->surface.format)) { 142 LOGD_IF(DEBUG_COPYBIT, "texture format not supported"); 143 return false; 144 } 145 return true; 146 } 147 148 149 static bool copybit(GLint x, GLint y, 150 GLint w, GLint h, 151 EGLTextureObject* textureObject, 152 const GLint* crop_rect, 153 int transform, 154 ogles_context_t* c) 155 { 156 status_t err = NO_ERROR; 157 158 // We assume checkContext has already been called and has already 159 // returned true. 160 161 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 162 163 y = cbSurface.height - (y + h); 164 165 const GLint Ucr = crop_rect[0]; 166 const GLint Vcr = crop_rect[1]; 167 const GLint Wcr = crop_rect[2]; 168 const GLint Hcr = crop_rect[3]; 169 170 GLint screen_w = w; 171 GLint screen_h = h; 172 int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt 173 int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht 174 if (transform & COPYBIT_TRANSFORM_ROT_90) { 175 swap(screen_w, screen_h); 176 } 177 if (dsdx!=screen_w || dtdy!=screen_h) { 178 // in most cases the divide is not needed 179 dsdx /= screen_w; 180 dtdy /= screen_h; 181 } 182 dtdy = -dtdy; // see equation of dtdy above 183 184 // copybit doesn't say anything about filtering, so we can't 185 // discriminate. On msm7k, copybit will always filter. 186 // the code below handles min/mag filters, we keep it as a reference. 187 188 #ifdef MIN_MAG_FILTER 189 int32_t texelArea = gglMulx(dtdy, dsdx); 190 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) { 191 // Non-linear filtering on a texture enlargement. 192 LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR"); 193 return false; 194 } 195 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) { 196 // Non-linear filtering on an texture shrink. 197 LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR"); 198 return false; 199 } 200 #endif 201 202 const uint32_t enables = c->rasterizer.state.enables; 203 int planeAlpha = 255; 204 bool alphaPlaneWorkaround = false; 205 static const int tmu = 0; 206 texture_t& tev(c->rasterizer.state.texture[tmu]); 207 int32_t opFormat = textureObject->surface.format; 208 const bool srcTextureHasAlpha = hasAlpha(opFormat); 209 if (!srcTextureHasAlpha) { 210 planeAlpha = fixedToByte(c->currentColorClamped.a); 211 } 212 213 const bool cbHasAlpha = hasAlpha(cbSurface.format); 214 bool blending = false; 215 if ((enables & GGL_ENABLE_BLENDING) 216 && !(c->rasterizer.state.blend.src == GL_ONE 217 && c->rasterizer.state.blend.dst == GL_ZERO)) { 218 // Blending is OK if it is 219 // the exact kind of blending that the copybits hardware supports. 220 // Note: The hardware only supports 221 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA, 222 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA. 223 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case, 224 // because the performance is worth it, even if the results are 225 // not correct. 226 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA 227 || c->rasterizer.state.blend.src == GL_ONE) 228 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA 229 && c->rasterizer.state.blend.alpha_separate == 0)) { 230 // Incompatible blend mode. 231 LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode"); 232 return false; 233 } 234 blending = true; 235 } else { 236 if (cbHasAlpha) { 237 // NOTE: the result will be slightly wrong in this case because 238 // the destination alpha channel will be set to 1.0 instead of 239 // the iterated alpha value. *shrug*. 240 } 241 // disable plane blending and src blending for supported formats 242 planeAlpha = 255; 243 if (opFormat == COPYBIT_FORMAT_RGBA_8888) { 244 opFormat = COPYBIT_FORMAT_RGBX_8888; 245 } else { 246 if (srcTextureHasAlpha) { 247 LOGD_IF(DEBUG_COPYBIT, "texture format requires blending"); 248 return false; 249 } 250 } 251 } 252 253 switch (tev.env) { 254 case GGL_REPLACE: 255 break; 256 case GGL_MODULATE: 257 // only cases allowed is: 258 // RGB source, color={1,1,1,a} -> can be done with GL_REPLACE 259 // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE 260 if (blending) { 261 if (c->currentColorClamped.r == c->currentColorClamped.a && 262 c->currentColorClamped.g == c->currentColorClamped.a && 263 c->currentColorClamped.b == c->currentColorClamped.a) { 264 // TODO: RGBA source, color={1,1,1,a} / regular-blending 265 // is equivalent 266 alphaPlaneWorkaround = true; 267 break; 268 } 269 } 270 LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE"); 271 return false; 272 default: 273 // Incompatible texture environment. 274 LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment"); 275 return false; 276 } 277 278 copybit_device_t* copybit = c->copybits.blitEngine; 279 copybit_image_t src; 280 textureToCopyBitImage(&textureObject->surface, opFormat, 281 textureObject->buffer, &src); 282 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr }; 283 284 /* 285 * Below we perform extra passes needed to emulate things the h/w 286 * cannot do. 287 */ 288 289 const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16); 290 const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16); 291 292 sp<GraphicBuffer> tempBitmap; 293 294 if (dsdx < maxScaleInv || dsdx > minScaleInv || 295 dtdy < maxScaleInv || dtdy > minScaleInv) 296 { 297 // The requested scale is out of the range the hardware 298 // can support. 299 LOGD_IF(DEBUG_COPYBIT, 300 "scale out of range dsdx=%08x (Wcr=%d / w=%d), " 301 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", 302 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); 303 304 int32_t xscale=0x10000, yscale=0x10000; 305 if (dsdx > minScaleInv) xscale = c->copybits.minScale; 306 else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale; 307 if (dtdy > minScaleInv) yscale = c->copybits.minScale; 308 else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale; 309 dsdx = gglMulx(dsdx, xscale); 310 dtdy = gglMulx(dtdy, yscale); 311 312 /* we handle only one step of resizing below. Handling an arbitrary 313 * number is relatively easy (replace "if" above by "while"), but requires 314 * two intermediate buffers and so far we never had the need. 315 */ 316 317 if (dsdx < maxScaleInv || dsdx > minScaleInv || 318 dtdy < maxScaleInv || dtdy > minScaleInv) { 319 LOGD_IF(DEBUG_COPYBIT, 320 "scale out of range dsdx=%08x (Wcr=%d / w=%d), " 321 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", 322 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); 323 return false; 324 } 325 326 const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16); 327 const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16); 328 329 LOGD_IF(DEBUG_COPYBIT, 330 "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d", 331 xscale, yscale, dsdx, dtdy, tmp_w, tmp_h); 332 333 tempBitmap = new GraphicBuffer( 334 tmp_w, tmp_h, src.format, 335 GraphicBuffer::USAGE_HW_2D); 336 337 err = tempBitmap->initCheck(); 338 if (err == NO_ERROR) { 339 copybit_image_t tmp_dst; 340 copybit_rect_t tmp_rect; 341 tmp_dst.w = tmp_w; 342 tmp_dst.h = tmp_h; 343 tmp_dst.format = tempBitmap->format; 344 tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle; 345 tmp_rect.l = 0; 346 tmp_rect.t = 0; 347 tmp_rect.r = tmp_dst.w; 348 tmp_rect.b = tmp_dst.h; 349 region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b))); 350 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); 351 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); 352 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); 353 err = copybit->stretch(copybit, 354 &tmp_dst, &src, &tmp_rect, &srect, &tmp_it); 355 src = tmp_dst; 356 srect = tmp_rect; 357 } 358 } 359 360 copybit_image_t dst; 361 textureToCopyBitImage(&cbSurface, cbSurface.format, 362 c->copybits.drawSurfaceBuffer, &dst); 363 copybit_rect_t drect = {x, y, x+w, y+h}; 364 365 366 /* and now the alpha-plane hack. This handles the "Fade" case of a 367 * texture with an alpha channel. 368 */ 369 if (alphaPlaneWorkaround) { 370 sp<GraphicBuffer> tempCb = new GraphicBuffer( 371 w, h, COPYBIT_FORMAT_RGB_565, 372 GraphicBuffer::USAGE_HW_2D); 373 374 err = tempCb->initCheck(); 375 376 copybit_image_t tmpCbImg; 377 copybit_rect_t tmpCbRect; 378 copybit_rect_t tmpdrect = drect; 379 tmpCbImg.w = w; 380 tmpCbImg.h = h; 381 tmpCbImg.format = tempCb->format; 382 tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle; 383 tmpCbRect.l = 0; 384 tmpCbRect.t = 0; 385 386 if (drect.l < 0) { 387 tmpCbRect.l = -tmpdrect.l; 388 tmpdrect.l = 0; 389 } 390 if (drect.t < 0) { 391 tmpCbRect.t = -tmpdrect.t; 392 tmpdrect.t = 0; 393 } 394 if (drect.l + tmpCbImg.w > dst.w) { 395 tmpCbImg.w = dst.w - drect.l; 396 tmpdrect.r = dst.w; 397 } 398 if (drect.t + tmpCbImg.h > dst.h) { 399 tmpCbImg.h = dst.h - drect.t; 400 tmpdrect.b = dst.h; 401 } 402 403 tmpCbRect.r = tmpCbImg.w; 404 tmpCbRect.b = tmpCbImg.h; 405 406 if (!err) { 407 // first make a copy of the destination buffer 408 region_iterator tmp_it(Region(Rect(w, h))); 409 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); 410 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); 411 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); 412 err = copybit->stretch(copybit, 413 &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it); 414 } 415 if (!err) { 416 // then proceed as usual, but without the alpha plane 417 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform); 418 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); 419 copybit->set_parameter(copybit, COPYBIT_DITHER, 420 (enables & GGL_ENABLE_DITHER) ? 421 COPYBIT_ENABLE : COPYBIT_DISABLE); 422 clipRectRegion it(c); 423 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it); 424 } 425 if (!err) { 426 // finally copy back the destination on top with 1-alphaplane 427 int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a); 428 clipRectRegion it(c); 429 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); 430 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha); 431 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); 432 err = copybit->stretch(copybit, 433 &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it); 434 } 435 } else { 436 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform); 437 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha); 438 copybit->set_parameter(copybit, COPYBIT_DITHER, 439 (enables & GGL_ENABLE_DITHER) ? 440 COPYBIT_ENABLE : COPYBIT_DISABLE); 441 clipRectRegion it(c); 442 443 LOGD_IF(0, 444 "dst={%d, %d, %d, %p, %p}, " 445 "src={%d, %d, %d, %p, %p}, " 446 "drect={%d,%d,%d,%d}, " 447 "srect={%d,%d,%d,%d}, " 448 "it={%d,%d,%d,%d}, " , 449 dst.w, dst.h, dst.format, dst.base, dst.handle, 450 src.w, src.h, src.format, src.base, src.handle, 451 drect.l, drect.t, drect.r, drect.b, 452 srect.l, srect.t, srect.r, srect.b, 453 it.r.l, it.r.t, it.r.r, it.r.b 454 ); 455 456 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it); 457 } 458 if (err != NO_ERROR) { 459 c->textures.tmu[0].texture->try_copybit = false; 460 } 461 return err == NO_ERROR ? true : false; 462 } 463 464 /* 465 * Try to draw a triangle fan with copybit, return false if we fail. 466 */ 467 bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count) 468 { 469 if (!checkContext(c)) { 470 return false; 471 } 472 473 // FIXME: we should handle culling here 474 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4); 475 476 // we detect if we're dealing with a rectangle, by comparing the 477 // rectangles {v0,v2} and {v1,v3} which should be identical. 478 479 // NOTE: we should check that the rectangle is window aligned, however 480 // if we do that, the optimization won't be taken in a lot of cases. 481 // Since this code is intended to be used with SurfaceFlinger only, 482 // so it's okay... 483 484 const vec4_t& v0 = c->vc.vBuffer[0].window; 485 const vec4_t& v1 = c->vc.vBuffer[1].window; 486 const vec4_t& v2 = c->vc.vBuffer[2].window; 487 const vec4_t& v3 = c->vc.vBuffer[3].window; 488 int l = min(v0.x, v2.x); 489 int b = min(v0.y, v2.y); 490 int r = max(v0.x, v2.x); 491 int t = max(v0.y, v2.y); 492 if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) || 493 (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) { 494 LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle"); 495 return false; 496 } 497 498 // fetch and transform texture coordinates 499 // NOTE: maybe it would be better to have a "compileElementsAll" method 500 // that would ensure all vertex data are fetched and transformed 501 const transform_t& tr = c->transforms.texture[0].transform; 502 for (size_t i=0 ; i<4 ; i++) { 503 const GLubyte* tp = c->arrays.texture[0].element(i); 504 vertex_t* const v = &c->vc.vBuffer[i]; 505 c->arrays.texture[0].fetch(c, v->texture[0].v, tp); 506 // FIXME: we should bail if q!=1 507 c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]); 508 } 509 510 const vec4_t& t0 = c->vc.vBuffer[0].texture[0]; 511 const vec4_t& t1 = c->vc.vBuffer[1].texture[0]; 512 const vec4_t& t2 = c->vc.vBuffer[2].texture[0]; 513 const vec4_t& t3 = c->vc.vBuffer[3].texture[0]; 514 int txl = min(t0.x, t2.x); 515 int txb = min(t0.y, t2.y); 516 int txr = max(t0.x, t2.x); 517 int txt = max(t0.y, t2.y); 518 if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) || 519 (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) { 520 LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle"); 521 return false; 522 } 523 if ((txl != 0) || (txb != 0) || 524 (txr != FIXED_ONE) || (txt != FIXED_ONE)) { 525 // we could probably handle this case, if we wanted to 526 LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x", 527 txl, txb, txr, txt); 528 return false; 529 } 530 531 // at this point, we know we are dealing with a rectangle, so we 532 // only need to consider 3 vertices for computing the jacobians 533 534 const int dx01 = v1.x - v0.x; 535 const int dx02 = v2.x - v0.x; 536 const int dy01 = v1.y - v0.y; 537 const int dy02 = v2.y - v0.y; 538 const int ds01 = t1.S - t0.S; 539 const int ds02 = t2.S - t0.S; 540 const int dt01 = t1.T - t0.T; 541 const int dt02 = t2.T - t0.T; 542 const int area = dx01*dy02 - dy01*dx02; 543 int dsdx, dsdy, dtdx, dtdy; 544 if (area >= 0) { 545 dsdx = ds01*dy02 - ds02*dy01; 546 dtdx = dt01*dy02 - dt02*dy01; 547 dsdy = ds02*dx01 - ds01*dx02; 548 dtdy = dt02*dx01 - dt01*dx02; 549 } else { 550 dsdx = ds02*dy01 - ds01*dy02; 551 dtdx = dt02*dy01 - dt01*dy02; 552 dsdy = ds01*dx02 - ds02*dx01; 553 dtdy = dt01*dx02 - dt02*dx01; 554 } 555 556 // here we rely on the fact that we know the transform is 557 // a rigid-body transform AND that it can only rotate in 90 degrees 558 // increments 559 560 int transform = 0; 561 if (dsdx == 0) { 562 // 90 deg rotation case 563 // [ 0 dtdx ] 564 // [ dsdx 0 ] 565 transform |= COPYBIT_TRANSFORM_ROT_90; 566 // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted 567 if (dtdx > 0) 568 transform |= COPYBIT_TRANSFORM_FLIP_H; 569 if (dsdy < 0) 570 transform |= COPYBIT_TRANSFORM_FLIP_V; 571 } else { 572 // [ dsdx 0 ] 573 // [ 0 dtdy ] 574 if (dsdx < 0) 575 transform |= COPYBIT_TRANSFORM_FLIP_H; 576 if (dtdy < 0) 577 transform |= COPYBIT_TRANSFORM_FLIP_V; 578 } 579 580 //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform); 581 //LOGD("A=%f\tB=%f\nC=%f\tD=%f", 582 // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0); 583 584 int x = l >> 4; 585 int y = b >> 4; 586 int w = (r-l) >> 4; 587 int h = (t-b) >> 4; 588 texture_unit_t& u(c->textures.tmu[0]); 589 EGLTextureObject* textureObject = u.texture; 590 GLint tWidth = textureObject->surface.width; 591 GLint tHeight = textureObject->surface.height; 592 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight}; 593 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; 594 y = cbSurface.height - (y + h); 595 return copybit(x, y, w, h, textureObject, crop_rect, transform, c); 596 } 597 598 /* 599 * Try to drawTexiOESWithCopybit, return false if we fail. 600 */ 601 602 bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z, 603 GLint w, GLint h, ogles_context_t* c) 604 { 605 // quickly process empty rects 606 if ((w|h) <= 0) { 607 return true; 608 } 609 if (!checkContext(c)) { 610 return false; 611 } 612 texture_unit_t& u(c->textures.tmu[0]); 613 EGLTextureObject* textureObject = u.texture; 614 return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c); 615 } 616 617 } // namespace android 618 619