blob: 4b9e59b7c885f1b77dd9364b8696f30a179cb5cb [file] [log] [blame]
Mathias Agopian1473f462009-04-10 14:24:30 -07001/*
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"
Mathias Agopian1473f462009-04-10 14:24:30 -070030#include "TextureObjectManager.h"
Mathias Agopian350d6512009-06-10 16:01:54 -070031
Mathias Agopian1473f462009-04-10 14:24:30 -070032#include <hardware/gralloc.h>
33#include <hardware/copybit.h>
Mathias Agopian350d6512009-06-10 16:01:54 -070034#include <private/ui/android_natives_priv.h>
Mathias Agopian1473f462009-04-10 14:24:30 -070035
Mathias Agopian9042b452009-10-26 20:12:37 -070036#include <ui/GraphicBuffer.h>
37#include <ui/Region.h>
38#include <ui/Rect.h>
39
Mathias Agopian03a1b012009-06-17 21:18:56 -070040
41#define DEBUG_COPYBIT true
42
Mathias Agopian1473f462009-04-10 14:24:30 -070043// ----------------------------------------------------------------------------
44
45namespace android {
46
Mathias Agopian350d6512009-06-10 16:01:54 -070047static void textureToCopyBitImage(
Mathias Agopian88d11cf2009-10-16 16:17:58 -070048 const GGLSurface* surface, int32_t opFormat,
49 buffer_handle_t buffer, copybit_image_t* img)
Mathias Agopian350d6512009-06-10 16:01:54 -070050{
Mathias Agopian1473f462009-04-10 14:24:30 -070051 img->w = surface->stride;
52 img->h = surface->height;
Mathias Agopian88d11cf2009-10-16 16:17:58 -070053 img->format = opFormat;
Mathias Agopian1473f462009-04-10 14:24:30 -070054 img->base = surface->data;
Mathias Agopian2eab9d82009-06-24 16:55:59 -070055 img->handle = (native_handle_t *)buffer;
Mathias Agopian1473f462009-04-10 14:24:30 -070056}
57
58struct clipRectRegion : public copybit_region_t {
Mathias Agopian4d63fb12009-06-16 18:08:29 -070059 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;
Mathias Agopian1473f462009-04-10 14:24:30 -070067 }
68private:
69 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
Mathias Agopian4d63fb12009-06-16 18:08:29 -070070 *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*) {
Mathias Agopian1473f462009-04-10 14:24:30 -070075 return 0;
76 }
Mathias Agopian4d63fb12009-06-16 18:08:29 -070077 copybit_rect_t r;
Mathias Agopian1473f462009-04-10 14:24:30 -070078};
79
80static bool supportedCopybitsFormat(int format) {
81 switch (format) {
82 case COPYBIT_FORMAT_RGBA_8888:
Mathias Agopianf1e5b0d2009-08-07 20:55:14 -070083 case COPYBIT_FORMAT_RGBX_8888:
84 case COPYBIT_FORMAT_RGB_888:
Mathias Agopian1473f462009-04-10 14:24:30 -070085 case COPYBIT_FORMAT_RGB_565:
86 case COPYBIT_FORMAT_BGRA_8888:
87 case COPYBIT_FORMAT_RGBA_5551:
88 case COPYBIT_FORMAT_RGBA_4444:
89 case COPYBIT_FORMAT_YCbCr_422_SP:
90 case COPYBIT_FORMAT_YCbCr_420_SP:
91 return true;
92 default:
93 return false;
94 }
95}
96
97static bool hasAlpha(int format) {
98 switch (format) {
99 case COPYBIT_FORMAT_RGBA_8888:
100 case COPYBIT_FORMAT_BGRA_8888:
101 case COPYBIT_FORMAT_RGBA_5551:
102 case COPYBIT_FORMAT_RGBA_4444:
103 return true;
104 default:
105 return false;
106 }
107}
108
109static inline int fixedToByte(GGLfixed val) {
110 return (val - (val >> 8)) >> 8;
111}
112
113/**
114 * Performs a quick check of the rendering state. If this function returns
115 * false we cannot use the copybit driver.
116 */
117
118static bool checkContext(ogles_context_t* c) {
119
Mathias Agopian350d6512009-06-10 16:01:54 -0700120 // By convention copybitQuickCheckContext() has already returned true.
Mathias Agopian1473f462009-04-10 14:24:30 -0700121 // avoid checking the same information again.
122
Mathias Agopian03a1b012009-06-17 21:18:56 -0700123 if (c->copybits.blitEngine == NULL) {
124 LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
125 return false;
126 }
127
128 if (c->rasterizer.state.enables
129 & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
130 LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
Mathias Agopian1473f462009-04-10 14:24:30 -0700131 return false;
132 }
133
Mathias Agopian350d6512009-06-10 16:01:54 -0700134 // Note: The drawSurfaceBuffer is only set for destination
Mathias Agopian1473f462009-04-10 14:24:30 -0700135 // surfaces types that are supported by the hardware and
136 // do not have an alpha channel. So we don't have to re-check that here.
137
138 static const int tmu = 0;
139 texture_unit_t& u(c->textures.tmu[tmu]);
140 EGLTextureObject* textureObject = u.texture;
141
142 if (!supportedCopybitsFormat(textureObject->surface.format)) {
Mathias Agopian03a1b012009-06-17 21:18:56 -0700143 LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
Mathias Agopian1473f462009-04-10 14:24:30 -0700144 return false;
145 }
146 return true;
147}
148
149
150static bool copybit(GLint x, GLint y,
151 GLint w, GLint h,
152 EGLTextureObject* textureObject,
153 const GLint* crop_rect,
154 int transform,
155 ogles_context_t* c)
156{
Mathias Agopian85ade332009-10-27 23:33:48 -0700157 status_t err = NO_ERROR;
158
Mathias Agopian1473f462009-04-10 14:24:30 -0700159 // We assume checkContext has already been called and has already
160 // returned true.
161
162 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
163
164 y = cbSurface.height - (y + h);
165
166 const GLint Ucr = crop_rect[0];
167 const GLint Vcr = crop_rect[1];
168 const GLint Wcr = crop_rect[2];
169 const GLint Hcr = crop_rect[3];
170
Mathias Agopian0f53af12009-06-29 16:36:49 -0700171 GLint screen_w = w;
172 GLint screen_h = h;
173 int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt
174 int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht
Mathias Agopianf6c2a1a2009-06-23 18:31:06 -0700175 if (transform & COPYBIT_TRANSFORM_ROT_90) {
Mathias Agopian0f53af12009-06-29 16:36:49 -0700176 swap(screen_w, screen_h);
Mathias Agopianf6c2a1a2009-06-23 18:31:06 -0700177 }
Mathias Agopian0f53af12009-06-29 16:36:49 -0700178 if (dsdx!=screen_w || dtdy!=screen_h) {
179 // in most cases the divide is not needed
180 dsdx /= screen_w;
181 dtdy /= screen_h;
182 }
183 dtdy = -dtdy; // see equation of dtdy above
Mathias Agopian1473f462009-04-10 14:24:30 -0700184
Mathias Agopian42bf6212009-06-17 21:58:18 -0700185 // copybit doesn't say anything about filtering, so we can't
186 // discriminate. On msm7k, copybit will always filter.
187 // the code below handles min/mag filters, we keep it as a reference.
188
189#ifdef MIN_MAG_FILTER
Mathias Agopian1473f462009-04-10 14:24:30 -0700190 int32_t texelArea = gglMulx(dtdy, dsdx);
191 if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
192 // Non-linear filtering on a texture enlargement.
Mathias Agopian03a1b012009-06-17 21:18:56 -0700193 LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
Mathias Agopian1473f462009-04-10 14:24:30 -0700194 return false;
195 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700196 if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
197 // Non-linear filtering on an texture shrink.
Mathias Agopian03a1b012009-06-17 21:18:56 -0700198 LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
Mathias Agopian1473f462009-04-10 14:24:30 -0700199 return false;
200 }
Mathias Agopian42bf6212009-06-17 21:58:18 -0700201#endif
202
Mathias Agopian1473f462009-04-10 14:24:30 -0700203 const uint32_t enables = c->rasterizer.state.enables;
204 int planeAlpha = 255;
Mathias Agopian85ade332009-10-27 23:33:48 -0700205 bool alphaPlaneWorkaround = false;
Mathias Agopian1473f462009-04-10 14:24:30 -0700206 static const int tmu = 0;
207 texture_t& tev(c->rasterizer.state.texture[tmu]);
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700208 int32_t opFormat = textureObject->surface.format;
209 const bool srcTextureHasAlpha = hasAlpha(opFormat);
Mathias Agopianf6c2a1a2009-06-23 18:31:06 -0700210 if (!srcTextureHasAlpha) {
211 planeAlpha = fixedToByte(c->currentColorClamped.a);
212 }
213
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700214 const bool cbHasAlpha = hasAlpha(cbSurface.format);
Mathias Agopian1473f462009-04-10 14:24:30 -0700215 bool blending = false;
Mathias Agopian1473f462009-04-10 14:24:30 -0700216 if ((enables & GGL_ENABLE_BLENDING)
217 && !(c->rasterizer.state.blend.src == GL_ONE
218 && c->rasterizer.state.blend.dst == GL_ZERO)) {
219 // Blending is OK if it is
220 // the exact kind of blending that the copybits hardware supports.
221 // Note: The hardware only supports
222 // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
223 // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
224 // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
225 // because the performance is worth it, even if the results are
226 // not correct.
227 if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
228 || c->rasterizer.state.blend.src == GL_ONE)
229 && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
230 && c->rasterizer.state.blend.alpha_separate == 0)) {
231 // Incompatible blend mode.
Mathias Agopian03a1b012009-06-17 21:18:56 -0700232 LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
Mathias Agopian1473f462009-04-10 14:24:30 -0700233 return false;
234 }
235 blending = true;
236 } else {
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700237 if (cbHasAlpha) {
238 // NOTE: the result will be slightly wrong in this case because
239 // the destination alpha channel will be set to 1.0 instead of
240 // the iterated alpha value. *shrug*.
241 }
242 // disable plane blending and src blending for supported formats
243 planeAlpha = 255;
244 if (opFormat == COPYBIT_FORMAT_RGBA_8888) {
245 opFormat = COPYBIT_FORMAT_RGBX_8888;
246 } else {
247 if (srcTextureHasAlpha) {
248 LOGD_IF(DEBUG_COPYBIT, "texture format requires blending");
249 return false;
250 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700251 }
252 }
253
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700254 switch (tev.env) {
255 case GGL_REPLACE:
256 break;
257 case GGL_MODULATE:
258 // only cases allowed is:
259 // RGB source, color={1,1,1,a} -> can be done with GL_REPLACE
260 // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE
261 if (blending) {
262 if (c->currentColorClamped.r == c->currentColorClamped.a &&
263 c->currentColorClamped.g == c->currentColorClamped.a &&
264 c->currentColorClamped.b == c->currentColorClamped.a) {
Mathias Agopian85ade332009-10-27 23:33:48 -0700265 // TODO: RGBA source, color={1,1,1,a} / regular-blending
266 // is equivalent
267 alphaPlaneWorkaround = true;
268 break;
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700269 }
270 }
271 LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE");
272 return false;
273 default:
274 // Incompatible texture environment.
275 LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
Mathias Agopian1473f462009-04-10 14:24:30 -0700276 return false;
277 }
278
Mathias Agopian1473f462009-04-10 14:24:30 -0700279 copybit_device_t* copybit = c->copybits.blitEngine;
Mathias Agopian9042b452009-10-26 20:12:37 -0700280 copybit_image_t src;
281 buffer_handle_t source_hnd = textureObject->buffer->handle;
282 textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
283 copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
284
285 /*
286 * Below we perform extra passes needed to emulate things the h/w
287 * cannot do.
288 */
289
290 const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
291 const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
292
293 sp<GraphicBuffer> tempBitmap;
294
295 if (dsdx < maxScaleInv || dsdx > minScaleInv ||
296 dtdy < maxScaleInv || dtdy > minScaleInv)
297 {
298 // The requested scale is out of the range the hardware
299 // can support.
300 LOGD_IF(DEBUG_COPYBIT,
301 "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
302 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
303 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
304
305 int32_t xscale=0x10000, yscale=0x10000;
306 if (dsdx > minScaleInv) xscale = c->copybits.minScale;
307 else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale;
308 if (dtdy > minScaleInv) yscale = c->copybits.minScale;
309 else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale;
310 dsdx = gglMulx(dsdx, xscale);
311 dtdy = gglMulx(dtdy, yscale);
312
313 /* we handle only one step of resizing below. Handling an arbitrary
314 * number is relatively easy (replace "if" above by "while"), but requires
315 * two intermediate buffers and so far we never had the need.
316 */
317
318 if (dsdx < maxScaleInv || dsdx > minScaleInv ||
319 dtdy < maxScaleInv || dtdy > minScaleInv) {
320 LOGD_IF(DEBUG_COPYBIT,
321 "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
322 "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
323 dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
324 return false;
325 }
326
327 const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
328 const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
329
330 LOGD_IF(DEBUG_COPYBIT,
331 "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
332 xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
333
334 tempBitmap = new GraphicBuffer(
335 tmp_w, tmp_h, src.format,
336 GraphicBuffer::USAGE_HW_2D);
337
Mathias Agopian85ade332009-10-27 23:33:48 -0700338 err = tempBitmap->initCheck();
Mathias Agopian9042b452009-10-26 20:12:37 -0700339 if (err == NO_ERROR) {
340 copybit_image_t tmp_dst;
341 copybit_rect_t tmp_rect;
342 tmp_dst.w = tmp_w;
343 tmp_dst.h = tmp_h;
Mathias Agopian85ade332009-10-27 23:33:48 -0700344 tmp_dst.format = tempBitmap->format;
Mathias Agopian9042b452009-10-26 20:12:37 -0700345 tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
346 tmp_rect.l = 0;
347 tmp_rect.t = 0;
348 tmp_rect.r = tmp_dst.w;
349 tmp_rect.b = tmp_dst.h;
350 region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
351 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
352 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
353 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
354 err = copybit->stretch(copybit,
355 &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
356 src = tmp_dst;
357 srect = tmp_rect;
358 }
359 }
Mathias Agopian350d6512009-06-10 16:01:54 -0700360
Mathias Agopian1473f462009-04-10 14:24:30 -0700361 copybit_image_t dst;
Mathias Agopian350d6512009-06-10 16:01:54 -0700362 buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
Mathias Agopian88d11cf2009-10-16 16:17:58 -0700363 textureToCopyBitImage(&cbSurface, cbSurface.format, target_hnd, &dst);
Mathias Agopian1473f462009-04-10 14:24:30 -0700364 copybit_rect_t drect = {x, y, x+w, y+h};
365
Mathias Agopian1473f462009-04-10 14:24:30 -0700366
Mathias Agopian85ade332009-10-27 23:33:48 -0700367 /* and now the alpha-plane hack. This handles the "Fade" case of a
368 * texture with an alpha channel.
369 */
370 if (alphaPlaneWorkaround) {
371 sp<GraphicBuffer> tempCb = new GraphicBuffer(
372 w, h, COPYBIT_FORMAT_RGB_565,
373 GraphicBuffer::USAGE_HW_2D);
374
375 err = tempCb->initCheck();
376
377 copybit_image_t tmpCbImg;
378 copybit_rect_t tmpCbRect;
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 tmpCbRect.r = w;
386 tmpCbRect.b = h;
387
388 if (!err) {
389 // first make a copy of the destination buffer
390 region_iterator tmp_it(Region(Rect(w, h)));
391 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
392 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
393 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
394 err = copybit->stretch(copybit,
395 &tmpCbImg, &dst, &tmpCbRect, &drect, &tmp_it);
396 }
397 if (!err) {
398 // then proceed as usual, but without the alpha plane
399 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
400 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
401 copybit->set_parameter(copybit, COPYBIT_DITHER,
402 (enables & GGL_ENABLE_DITHER) ?
403 COPYBIT_ENABLE : COPYBIT_DISABLE);
404 clipRectRegion it(c);
405 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
406 }
407 if (!err) {
408 // finally copy back the destination on top with 1-alphaplane
409 int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a);
410 clipRectRegion it(c);
411 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
412 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha);
413 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
414 err = copybit->stretch(copybit,
415 &dst, &tmpCbImg, &drect, &tmpCbRect, &it);
416 }
417 } else {
418 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
419 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
420 copybit->set_parameter(copybit, COPYBIT_DITHER,
421 (enables & GGL_ENABLE_DITHER) ?
422 COPYBIT_ENABLE : COPYBIT_DISABLE);
423 clipRectRegion it(c);
424 err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
425 }
Mathias Agopiana2fb72e2009-07-15 18:53:32 -0700426 if (err != NO_ERROR) {
427 c->textures.tmu[0].texture->try_copybit = false;
428 }
Mathias Agopian0f53af12009-06-29 16:36:49 -0700429 return err == NO_ERROR ? true : false;
Mathias Agopian1473f462009-04-10 14:24:30 -0700430}
431
432/*
433 * Try to draw a triangle fan with copybit, return false if we fail.
434 */
Mathias Agopian03a1b012009-06-17 21:18:56 -0700435bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
436{
437 if (!checkContext(c)) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700438 return false;
439 }
440
Mathias Agopian09cf0ac2009-06-18 19:31:07 -0700441 // FIXME: we should handle culling here
Mathias Agopian1473f462009-04-10 14:24:30 -0700442 c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
Mathias Agopian1473f462009-04-10 14:24:30 -0700443
Mathias Agopian03a1b012009-06-17 21:18:56 -0700444 // we detect if we're dealing with a rectangle, by comparing the
445 // rectangles {v0,v2} and {v1,v3} which should be identical.
446
Mathias Agopian42bf6212009-06-17 21:58:18 -0700447 // NOTE: we should check that the rectangle is window aligned, however
448 // if we do that, the optimization won't be taken in a lot of cases.
449 // Since this code is intended to be used with SurfaceFlinger only,
450 // so it's okay...
451
Mathias Agopian03a1b012009-06-17 21:18:56 -0700452 const vec4_t& v0 = c->vc.vBuffer[0].window;
453 const vec4_t& v1 = c->vc.vBuffer[1].window;
454 const vec4_t& v2 = c->vc.vBuffer[2].window;
455 const vec4_t& v3 = c->vc.vBuffer[3].window;
456 int l = min(v0.x, v2.x);
457 int b = min(v0.y, v2.y);
458 int r = max(v0.x, v2.x);
459 int t = max(v0.y, v2.y);
460 if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
461 (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
462 LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
Mathias Agopian1473f462009-04-10 14:24:30 -0700463 return false;
464 }
Mathias Agopian09cf0ac2009-06-18 19:31:07 -0700465
466 // fetch and transform texture coordinates
467 // NOTE: maybe it would be better to have a "compileElementsAll" method
468 // that would ensure all vertex data are fetched and transformed
469 const transform_t& tr = c->transforms.texture[0].transform;
470 for (size_t i=0 ; i<4 ; i++) {
471 const GLubyte* tp = c->arrays.texture[0].element(i);
472 vertex_t* const v = &c->vc.vBuffer[i];
473 c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
474 // FIXME: we should bail if q!=1
475 c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
476 }
Mathias Agopian03a1b012009-06-17 21:18:56 -0700477
478 const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
479 const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
480 const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
481 const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
482 int txl = min(t0.x, t2.x);
483 int txb = min(t0.y, t2.y);
484 int txr = max(t0.x, t2.x);
485 int txt = max(t0.y, t2.y);
486 if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
487 (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
488 LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
489 return false;
490 }
491 if ((txl != 0) || (txb != 0) ||
492 (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
493 // we could probably handle this case, if we wanted to
Mathias Agopian09cf0ac2009-06-18 19:31:07 -0700494 LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
495 txl, txb, txr, txt);
Mathias Agopian1473f462009-04-10 14:24:30 -0700496 return false;
497 }
498
Mathias Agopian03a1b012009-06-17 21:18:56 -0700499 // at this point, we know we are dealing with a rectangle, so we
500 // only need to consider 3 vertices for computing the jacobians
501
502 const int dx01 = v1.x - v0.x;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700503 const int dx02 = v2.x - v0.x;
Mathias Agopian0f53af12009-06-29 16:36:49 -0700504 const int dy01 = v1.y - v0.y;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700505 const int dy02 = v2.y - v0.y;
506 const int ds01 = t1.S - t0.S;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700507 const int ds02 = t2.S - t0.S;
Mathias Agopian0f53af12009-06-29 16:36:49 -0700508 const int dt01 = t1.T - t0.T;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700509 const int dt02 = t2.T - t0.T;
510 const int area = dx01*dy02 - dy01*dx02;
511 int dsdx, dsdy, dtdx, dtdy;
512 if (area >= 0) {
513 dsdx = ds01*dy02 - ds02*dy01;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700514 dtdx = dt01*dy02 - dt02*dy01;
Mathias Agopian0f53af12009-06-29 16:36:49 -0700515 dsdy = ds02*dx01 - ds01*dx02;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700516 dtdy = dt02*dx01 - dt01*dx02;
517 } else {
518 dsdx = ds02*dy01 - ds01*dy02;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700519 dtdx = dt02*dy01 - dt01*dy02;
Mathias Agopian0f53af12009-06-29 16:36:49 -0700520 dsdy = ds01*dx02 - ds02*dx01;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700521 dtdy = dt01*dx02 - dt02*dx01;
Mathias Agopian1473f462009-04-10 14:24:30 -0700522 }
523
Mathias Agopian03a1b012009-06-17 21:18:56 -0700524 // here we rely on the fact that we know the transform is
525 // a rigid-body transform AND that it can only rotate in 90 degrees
526 // increments
527
528 int transform = 0;
529 if (dsdx == 0) {
530 // 90 deg rotation case
531 // [ 0 dtdx ]
532 // [ dsdx 0 ]
533 transform |= COPYBIT_TRANSFORM_ROT_90;
534 // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
535 if (dtdx > 0)
536 transform |= COPYBIT_TRANSFORM_FLIP_H;
537 if (dsdy < 0)
538 transform |= COPYBIT_TRANSFORM_FLIP_V;
539 } else {
540 // [ dsdx 0 ]
541 // [ 0 dtdy ]
542 if (dsdx < 0)
543 transform |= COPYBIT_TRANSFORM_FLIP_H;
544 if (dtdy < 0)
545 transform |= COPYBIT_TRANSFORM_FLIP_V;
546 }
547
548 //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
549 //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
550 // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
551
552 int x = l >> 4;
553 int y = b >> 4;
554 int w = (r-l) >> 4;
555 int h = (t-b) >> 4;
556 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian1473f462009-04-10 14:24:30 -0700557 EGLTextureObject* textureObject = u.texture;
Mathias Agopian1473f462009-04-10 14:24:30 -0700558 GLint tWidth = textureObject->surface.width;
559 GLint tHeight = textureObject->surface.height;
560 GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
Mathias Agopian1473f462009-04-10 14:24:30 -0700561 const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
562 y = cbSurface.height - (y + h);
Mathias Agopian03a1b012009-06-17 21:18:56 -0700563 return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
Mathias Agopian1473f462009-04-10 14:24:30 -0700564}
565
566/*
567 * Try to drawTexiOESWithCopybit, return false if we fail.
568 */
569
570bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
571 GLint w, GLint h, ogles_context_t* c)
572{
573 // quickly process empty rects
574 if ((w|h) <= 0) {
575 return true;
576 }
Mathias Agopian03a1b012009-06-17 21:18:56 -0700577 if (!checkContext(c)) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700578 return false;
579 }
Mathias Agopian03a1b012009-06-17 21:18:56 -0700580 texture_unit_t& u(c->textures.tmu[0]);
Mathias Agopian1473f462009-04-10 14:24:30 -0700581 EGLTextureObject* textureObject = u.texture;
Mathias Agopian03a1b012009-06-17 21:18:56 -0700582 return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
Mathias Agopian1473f462009-04-10 14:24:30 -0700583}
584
585} // namespace android
586