glamor_largepixmap.c 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. #include <stdlib.h>
  2. #include "glamor_priv.h"
  3. /**
  4. * Clip the boxes regards to each pixmap's block array.
  5. *
  6. * Should translate the region to relative coords to the pixmap,
  7. * start at (0,0).
  8. */
  9. #if 0
  10. //#define DEBUGF(str, ...) do {} while(0)
  11. #define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
  12. //#define DEBUGRegionPrint(x) do {} while (0)
  13. #define DEBUGRegionPrint RegionPrint
  14. #endif
  15. static glamor_pixmap_clipped_regions *
  16. __glamor_compute_clipped_regions(int block_w,
  17. int block_h,
  18. int block_stride,
  19. int x, int y,
  20. int w, int h,
  21. RegionPtr region,
  22. int *n_region, int reverse, int upsidedown)
  23. {
  24. glamor_pixmap_clipped_regions *clipped_regions;
  25. BoxPtr extent;
  26. int start_x, start_y, end_x, end_y;
  27. int start_block_x, start_block_y;
  28. int end_block_x, end_block_y;
  29. int loop_start_block_x, loop_start_block_y;
  30. int loop_end_block_x, loop_end_block_y;
  31. int loop_block_stride;
  32. int i, j, delta_i, delta_j;
  33. RegionRec temp_region;
  34. RegionPtr current_region;
  35. int block_idx;
  36. int k = 0;
  37. int temp_block_idx;
  38. extent = RegionExtents(region);
  39. start_x = MAX(x, extent->x1);
  40. start_y = MAX(y, extent->y1);
  41. end_x = MIN(x + w, extent->x2);
  42. end_y = MIN(y + h, extent->y2);
  43. DEBUGF("start compute clipped regions:\n");
  44. DEBUGF("block w %d h %d x %d y %d w %d h %d, block_stride %d \n",
  45. block_w, block_h, x, y, w, h, block_stride);
  46. DEBUGRegionPrint(region);
  47. DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y,
  48. end_x, end_y);
  49. if (start_x >= end_x || start_y >= end_y) {
  50. *n_region = 0;
  51. return NULL;
  52. }
  53. start_block_x = (start_x - x) / block_w;
  54. start_block_y = (start_y - y) / block_h;
  55. end_block_x = (end_x - x) / block_w;
  56. end_block_y = (end_y - y) / block_h;
  57. clipped_regions = calloc((end_block_x - start_block_x + 1)
  58. * (end_block_y - start_block_y + 1),
  59. sizeof(*clipped_regions));
  60. DEBUGF("startx %d starty %d endx %d endy %d \n",
  61. start_x, start_y, end_x, end_y);
  62. DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x);
  63. DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y);
  64. if (!reverse) {
  65. loop_start_block_x = start_block_x;
  66. loop_end_block_x = end_block_x + 1;
  67. delta_i = 1;
  68. }
  69. else {
  70. loop_start_block_x = end_block_x;
  71. loop_end_block_x = start_block_x - 1;
  72. delta_i = -1;
  73. }
  74. if (!upsidedown) {
  75. loop_start_block_y = start_block_y;
  76. loop_end_block_y = end_block_y + 1;
  77. delta_j = 1;
  78. }
  79. else {
  80. loop_start_block_y = end_block_y;
  81. loop_end_block_y = start_block_y - 1;
  82. delta_j = -1;
  83. }
  84. loop_block_stride = delta_j * block_stride;
  85. block_idx = (loop_start_block_y - delta_j) * block_stride;
  86. for (j = loop_start_block_y; j != loop_end_block_y; j += delta_j) {
  87. block_idx += loop_block_stride;
  88. temp_block_idx = block_idx + loop_start_block_x;
  89. for (i = loop_start_block_x;
  90. i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i) {
  91. BoxRec temp_box;
  92. temp_box.x1 = x + i * block_w;
  93. temp_box.y1 = y + j * block_h;
  94. temp_box.x2 = MIN(temp_box.x1 + block_w, end_x);
  95. temp_box.y2 = MIN(temp_box.y1 + block_h, end_y);
  96. RegionInitBoxes(&temp_region, &temp_box, 1);
  97. DEBUGF("block idx %d \n", temp_block_idx);
  98. DEBUGRegionPrint(&temp_region);
  99. current_region = RegionCreate(NULL, 4);
  100. RegionIntersect(current_region, &temp_region, region);
  101. DEBUGF("i %d j %d region: \n", i, j);
  102. DEBUGRegionPrint(current_region);
  103. if (RegionNumRects(current_region)) {
  104. clipped_regions[k].region = current_region;
  105. clipped_regions[k].block_idx = temp_block_idx;
  106. k++;
  107. }
  108. else
  109. RegionDestroy(current_region);
  110. RegionUninit(&temp_region);
  111. }
  112. }
  113. *n_region = k;
  114. return clipped_regions;
  115. }
  116. /**
  117. * Do a two round clipping,
  118. * first is to clip the region regard to current pixmap's
  119. * block array. Then for each clipped region, do a inner
  120. * block clipping. This is to make sure the final result
  121. * will be shapped by inner_block_w and inner_block_h, and
  122. * the final region also will not cross the pixmap's block
  123. * boundary.
  124. *
  125. * This is mainly used by transformation support when do
  126. * compositing.
  127. */
  128. glamor_pixmap_clipped_regions *
  129. glamor_compute_clipped_regions_ext(glamor_pixmap_private *pixmap_priv,
  130. RegionPtr region,
  131. int *n_region,
  132. int inner_block_w, int inner_block_h,
  133. int reverse, int upsidedown)
  134. {
  135. glamor_pixmap_clipped_regions *clipped_regions, *inner_regions,
  136. *result_regions;
  137. int i, j, x, y, k, inner_n_regions;
  138. int width, height;
  139. glamor_pixmap_private_large_t *priv;
  140. priv = &pixmap_priv->large;
  141. DEBUGF("ext called \n");
  142. if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
  143. clipped_regions = calloc(1, sizeof(*clipped_regions));
  144. if (clipped_regions == NULL) {
  145. *n_region = 0;
  146. return NULL;
  147. }
  148. clipped_regions[0].region = RegionCreate(NULL, 1);
  149. clipped_regions[0].block_idx = 0;
  150. RegionCopy(clipped_regions[0].region, region);
  151. *n_region = 1;
  152. priv->block_w = priv->base.pixmap->drawable.width;
  153. priv->block_h = priv->base.pixmap->drawable.height;
  154. priv->box_array = &priv->box;
  155. priv->box.x1 = priv->box.y1 = 0;
  156. priv->box.x2 = priv->block_w;
  157. priv->box.y2 = priv->block_h;
  158. }
  159. else {
  160. clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
  161. priv->block_h,
  162. priv->block_wcnt,
  163. 0, 0,
  164. priv->base.pixmap->
  165. drawable.width,
  166. priv->base.pixmap->
  167. drawable.height,
  168. region, n_region,
  169. reverse, upsidedown);
  170. if (clipped_regions == NULL) {
  171. *n_region = 0;
  172. return NULL;
  173. }
  174. }
  175. if (inner_block_w >= priv->block_w && inner_block_h >= priv->block_h)
  176. return clipped_regions;
  177. result_regions = calloc(*n_region
  178. * ((priv->block_w + inner_block_w - 1) /
  179. inner_block_w)
  180. * ((priv->block_h + inner_block_h - 1) /
  181. inner_block_h), sizeof(*result_regions));
  182. k = 0;
  183. for (i = 0; i < *n_region; i++) {
  184. x = priv->box_array[clipped_regions[i].block_idx].x1;
  185. y = priv->box_array[clipped_regions[i].block_idx].y1;
  186. width = priv->box_array[clipped_regions[i].block_idx].x2 - x;
  187. height = priv->box_array[clipped_regions[i].block_idx].y2 - y;
  188. inner_regions = __glamor_compute_clipped_regions(inner_block_w,
  189. inner_block_h,
  190. 0, x, y,
  191. width,
  192. height,
  193. clipped_regions[i].
  194. region,
  195. &inner_n_regions,
  196. reverse, upsidedown);
  197. for (j = 0; j < inner_n_regions; j++) {
  198. result_regions[k].region = inner_regions[j].region;
  199. result_regions[k].block_idx = clipped_regions[i].block_idx;
  200. k++;
  201. }
  202. free(inner_regions);
  203. }
  204. *n_region = k;
  205. free(clipped_regions);
  206. return result_regions;
  207. }
  208. /*
  209. *
  210. * For the repeat pad mode, we can simply convert the region and
  211. * let the out-of-box region can cover the needed edge of the source/mask
  212. * Then apply a normal clip we can get what we want.
  213. */
  214. static RegionPtr
  215. _glamor_convert_pad_region(RegionPtr region, int w, int h)
  216. {
  217. RegionPtr pad_region;
  218. int nrect;
  219. BoxPtr box;
  220. int overlap;
  221. nrect = RegionNumRects(region);
  222. box = RegionRects(region);
  223. pad_region = RegionCreate(NULL, 4);
  224. if (pad_region == NULL)
  225. return NULL;
  226. while (nrect--) {
  227. BoxRec pad_box;
  228. RegionRec temp_region;
  229. pad_box = *box;
  230. if (pad_box.x1 < 0 && pad_box.x2 <= 0)
  231. pad_box.x2 = 1;
  232. else if (pad_box.x1 >= w && pad_box.x2 > w)
  233. pad_box.x1 = w - 1;
  234. if (pad_box.y1 < 0 && pad_box.y2 <= 0)
  235. pad_box.y2 = 1;
  236. else if (pad_box.y1 >= h && pad_box.y2 > h)
  237. pad_box.y1 = h - 1;
  238. RegionInitBoxes(&temp_region, &pad_box, 1);
  239. RegionAppend(pad_region, &temp_region);
  240. RegionUninit(&temp_region);
  241. box++;
  242. }
  243. RegionValidate(pad_region, &overlap);
  244. return pad_region;
  245. }
  246. /*
  247. * For one type of large pixmap, its one direction is not exceed the
  248. * size limitation, and in another word, on one direction it has only
  249. * one block.
  250. *
  251. * This case of reflect repeating, we can optimize it and avoid repeat
  252. * clip on that direction. We can just enlarge the repeat box and can
  253. * cover all the dest region on that direction. But latter, we need to
  254. * fixup the clipped result to get a correct coords for the subsequent
  255. * processing. This function is to do the coords correction.
  256. *
  257. * */
  258. static void
  259. _glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh)
  260. {
  261. int odd1, odd2;
  262. int c1, c2;
  263. if (*xy2 - *xy1 > wh) {
  264. *xy1 = 0;
  265. *xy2 = wh;
  266. return;
  267. }
  268. modulus(*xy1, wh, c1);
  269. odd1 = ((*xy1 - c1) / wh) & 0x1;
  270. modulus(*xy2, wh, c2);
  271. odd2 = ((*xy2 - c2) / wh) & 0x1;
  272. if (odd1 && odd2) {
  273. *xy1 = wh - c2;
  274. *xy2 = wh - c1;
  275. }
  276. else if (odd1 && !odd2) {
  277. *xy1 = 0;
  278. *xy2 = MAX(c2, wh - c1);
  279. }
  280. else if (!odd1 && odd2) {
  281. *xy2 = wh;
  282. *xy1 = MIN(c1, wh - c2);
  283. }
  284. else {
  285. *xy1 = c1;
  286. *xy2 = c2;
  287. }
  288. }
  289. /**
  290. * Clip the boxes regards to each pixmap's block array.
  291. *
  292. * Should translate the region to relative coords to the pixmap,
  293. * start at (0,0).
  294. *
  295. * @is_transform: if it is set, it has a transform matrix.
  296. *
  297. */
  298. static glamor_pixmap_clipped_regions *
  299. _glamor_compute_clipped_regions(glamor_pixmap_private *pixmap_priv,
  300. RegionPtr region, int *n_region,
  301. int repeat_type, int is_transform,
  302. int reverse, int upsidedown)
  303. {
  304. glamor_pixmap_clipped_regions *clipped_regions;
  305. BoxPtr extent;
  306. int i, j;
  307. RegionPtr current_region;
  308. int pixmap_width, pixmap_height;
  309. int m;
  310. BoxRec repeat_box;
  311. RegionRec repeat_region;
  312. int right_shift = 0;
  313. int down_shift = 0;
  314. int x_center_shift = 0, y_center_shift = 0;
  315. glamor_pixmap_private_large_t *priv;
  316. priv = &pixmap_priv->large;
  317. DEBUGRegionPrint(region);
  318. if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
  319. clipped_regions = calloc(1, sizeof(*clipped_regions));
  320. clipped_regions[0].region = RegionCreate(NULL, 1);
  321. clipped_regions[0].block_idx = 0;
  322. RegionCopy(clipped_regions[0].region, region);
  323. *n_region = 1;
  324. return clipped_regions;
  325. }
  326. pixmap_width = priv->base.pixmap->drawable.width;
  327. pixmap_height = priv->base.pixmap->drawable.height;
  328. if (repeat_type == 0 || repeat_type == RepeatPad) {
  329. RegionPtr saved_region = NULL;
  330. if (repeat_type == RepeatPad) {
  331. saved_region = region;
  332. region =
  333. _glamor_convert_pad_region(saved_region, pixmap_width,
  334. pixmap_height);
  335. if (region == NULL) {
  336. *n_region = 0;
  337. return NULL;
  338. }
  339. }
  340. clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
  341. priv->block_h,
  342. priv->block_wcnt,
  343. 0, 0,
  344. priv->base.pixmap->
  345. drawable.width,
  346. priv->base.pixmap->
  347. drawable.height,
  348. region, n_region,
  349. reverse, upsidedown);
  350. if (saved_region)
  351. RegionDestroy(region);
  352. return clipped_regions;
  353. }
  354. extent = RegionExtents(region);
  355. x_center_shift = extent->x1 / pixmap_width;
  356. if (x_center_shift < 0)
  357. x_center_shift--;
  358. if (abs(x_center_shift) & 1)
  359. x_center_shift++;
  360. y_center_shift = extent->y1 / pixmap_height;
  361. if (y_center_shift < 0)
  362. y_center_shift--;
  363. if (abs(y_center_shift) & 1)
  364. y_center_shift++;
  365. if (extent->x1 < 0)
  366. right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width);
  367. if (extent->y1 < 0)
  368. down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height);
  369. if (right_shift != 0 || down_shift != 0) {
  370. if (repeat_type == RepeatReflect) {
  371. right_shift = (right_shift + 1) & ~1;
  372. down_shift = (down_shift + 1) & ~1;
  373. }
  374. RegionTranslate(region, right_shift * pixmap_width,
  375. down_shift * pixmap_height);
  376. }
  377. extent = RegionExtents(region);
  378. /* Tile a large pixmap to another large pixmap.
  379. * We can't use the target large pixmap as the
  380. * loop variable, instead we need to loop for all
  381. * the blocks in the tile pixmap.
  382. *
  383. * simulate repeat each single block to cover the
  384. * target's blocks. Two special case:
  385. * a block_wcnt == 1 or block_hcnt ==1, then we
  386. * only need to loop one direction as the other
  387. * direction is fully included in the first block.
  388. *
  389. * For the other cases, just need to start
  390. * from a proper shiftx/shifty, and then increase
  391. * y by tile_height each time to walk trhough the
  392. * target block and then walk trhough the target
  393. * at x direction by increate tile_width each time.
  394. *
  395. * This way, we can consolidate all the sub blocks
  396. * of the target boxes into one tile source's block.
  397. *
  398. * */
  399. m = 0;
  400. clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt,
  401. sizeof(*clipped_regions));
  402. if (clipped_regions == NULL) {
  403. *n_region = 0;
  404. return NULL;
  405. }
  406. if (right_shift != 0 || down_shift != 0) {
  407. DEBUGF("region to be repeated shifted \n");
  408. DEBUGRegionPrint(region);
  409. }
  410. DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height);
  411. DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1,
  412. extent->x2, extent->y2);
  413. for (j = 0; j < priv->block_hcnt; j++) {
  414. for (i = 0; i < priv->block_wcnt; i++) {
  415. int dx = pixmap_width;
  416. int dy = pixmap_height;
  417. int idx;
  418. int shift_x;
  419. int shift_y;
  420. int saved_y1, saved_y2;
  421. int x_idx = 0, y_idx = 0, saved_y_idx = 0;
  422. RegionRec temp_region;
  423. BoxRec reflect_repeat_box;
  424. BoxPtr valid_repeat_box;
  425. shift_x = (extent->x1 / pixmap_width) * pixmap_width;
  426. shift_y = (extent->y1 / pixmap_height) * pixmap_height;
  427. idx = j * priv->block_wcnt + i;
  428. if (repeat_type == RepeatReflect) {
  429. x_idx = (extent->x1 / pixmap_width);
  430. y_idx = (extent->y1 / pixmap_height);
  431. }
  432. /* Construct a rect to clip the target region. */
  433. repeat_box.x1 = shift_x + priv->box_array[idx].x1;
  434. repeat_box.y1 = shift_y + priv->box_array[idx].y1;
  435. if (priv->block_wcnt == 1) {
  436. repeat_box.x2 = extent->x2;
  437. dx = extent->x2 - repeat_box.x1;
  438. }
  439. else
  440. repeat_box.x2 = shift_x + priv->box_array[idx].x2;
  441. if (priv->block_hcnt == 1) {
  442. repeat_box.y2 = extent->y2;
  443. dy = extent->y2 - repeat_box.y1;
  444. }
  445. else
  446. repeat_box.y2 = shift_y + priv->box_array[idx].y2;
  447. current_region = RegionCreate(NULL, 4);
  448. RegionInit(&temp_region, NULL, 4);
  449. DEBUGF("init repeat box %d %d %d %d \n",
  450. repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
  451. if (repeat_type == RepeatNormal) {
  452. saved_y1 = repeat_box.y1;
  453. saved_y2 = repeat_box.y2;
  454. for (; repeat_box.x1 < extent->x2;
  455. repeat_box.x1 += dx, repeat_box.x2 += dx) {
  456. repeat_box.y1 = saved_y1;
  457. repeat_box.y2 = saved_y2;
  458. for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
  459. repeat_box.y1 < extent->y2;
  460. repeat_box.y1 += dy, repeat_box.y2 += dy) {
  461. RegionInitBoxes(&repeat_region, &repeat_box, 1);
  462. DEBUGF("Start to clip repeat region: \n");
  463. DEBUGRegionPrint(&repeat_region);
  464. RegionIntersect(&temp_region, &repeat_region, region);
  465. DEBUGF("clip result:\n");
  466. DEBUGRegionPrint(&temp_region);
  467. RegionAppend(current_region, &temp_region);
  468. RegionUninit(&repeat_region);
  469. }
  470. }
  471. }
  472. else if (repeat_type == RepeatReflect) {
  473. saved_y1 = repeat_box.y1;
  474. saved_y2 = repeat_box.y2;
  475. saved_y_idx = y_idx;
  476. for (;; repeat_box.x1 += dx, repeat_box.x2 += dx) {
  477. repeat_box.y1 = saved_y1;
  478. repeat_box.y2 = saved_y2;
  479. y_idx = saved_y_idx;
  480. reflect_repeat_box.x1 = (x_idx & 1) ?
  481. ((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1;
  482. reflect_repeat_box.x2 = (x_idx & 1) ?
  483. ((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2;
  484. valid_repeat_box = &reflect_repeat_box;
  485. if (valid_repeat_box->x1 >= extent->x2)
  486. break;
  487. for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;;
  488. repeat_box.y1 += dy, repeat_box.y2 += dy) {
  489. DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx,
  490. dx, dy);
  491. DEBUGF("repeat box %d %d %d %d \n", repeat_box.x1,
  492. repeat_box.y1, repeat_box.x2, repeat_box.y2);
  493. if (priv->block_hcnt > 1) {
  494. reflect_repeat_box.y1 = (y_idx & 1) ?
  495. ((2 * y_idx + 1) * dy -
  496. repeat_box.y2) : repeat_box.y1;
  497. reflect_repeat_box.y2 =
  498. (y_idx & 1) ? ((2 * y_idx + 1) * dy -
  499. repeat_box.y1) : repeat_box.y2;
  500. }
  501. else {
  502. reflect_repeat_box.y1 = repeat_box.y1;
  503. reflect_repeat_box.y2 = repeat_box.y2;
  504. }
  505. DEBUGF("valid_repeat_box x1 %d y1 %d \n",
  506. valid_repeat_box->x1, valid_repeat_box->y1);
  507. if (valid_repeat_box->y1 >= extent->y2)
  508. break;
  509. RegionInitBoxes(&repeat_region, valid_repeat_box, 1);
  510. DEBUGF("start to clip repeat[reflect] region: \n");
  511. DEBUGRegionPrint(&repeat_region);
  512. RegionIntersect(&temp_region, &repeat_region, region);
  513. DEBUGF("result:\n");
  514. DEBUGRegionPrint(&temp_region);
  515. if (is_transform && RegionNumRects(&temp_region)) {
  516. BoxRec temp_box;
  517. BoxPtr temp_extent;
  518. temp_extent = RegionExtents(&temp_region);
  519. if (priv->block_wcnt > 1) {
  520. if (x_idx & 1) {
  521. temp_box.x1 =
  522. ((2 * x_idx + 1) * dx -
  523. temp_extent->x2);
  524. temp_box.x2 =
  525. ((2 * x_idx + 1) * dx -
  526. temp_extent->x1);
  527. }
  528. else {
  529. temp_box.x1 = temp_extent->x1;
  530. temp_box.x2 = temp_extent->x2;
  531. }
  532. modulus(temp_box.x1, pixmap_width, temp_box.x1);
  533. modulus(temp_box.x2, pixmap_width, temp_box.x2);
  534. if (temp_box.x2 == 0)
  535. temp_box.x2 = pixmap_width;
  536. }
  537. else {
  538. temp_box.x1 = temp_extent->x1;
  539. temp_box.x2 = temp_extent->x2;
  540. _glamor_largepixmap_reflect_fixup(&temp_box.x1,
  541. &temp_box.x2,
  542. pixmap_width);
  543. }
  544. if (priv->block_hcnt > 1) {
  545. if (y_idx & 1) {
  546. temp_box.y1 =
  547. ((2 * y_idx + 1) * dy -
  548. temp_extent->y2);
  549. temp_box.y2 =
  550. ((2 * y_idx + 1) * dy -
  551. temp_extent->y1);
  552. }
  553. else {
  554. temp_box.y1 = temp_extent->y1;
  555. temp_box.y2 = temp_extent->y2;
  556. }
  557. modulus(temp_box.y1, pixmap_height,
  558. temp_box.y1);
  559. modulus(temp_box.y2, pixmap_height,
  560. temp_box.y2);
  561. if (temp_box.y2 == 0)
  562. temp_box.y2 = pixmap_height;
  563. }
  564. else {
  565. temp_box.y1 = temp_extent->y1;
  566. temp_box.y2 = temp_extent->y2;
  567. _glamor_largepixmap_reflect_fixup(&temp_box.y1,
  568. &temp_box.y2,
  569. pixmap_height);
  570. }
  571. RegionInitBoxes(&temp_region, &temp_box, 1);
  572. RegionTranslate(&temp_region,
  573. x_center_shift * pixmap_width,
  574. y_center_shift * pixmap_height);
  575. DEBUGF("for transform result:\n");
  576. DEBUGRegionPrint(&temp_region);
  577. }
  578. RegionAppend(current_region, &temp_region);
  579. RegionUninit(&repeat_region);
  580. y_idx++;
  581. }
  582. x_idx++;
  583. }
  584. }
  585. DEBUGF("dx %d dy %d \n", dx, dy);
  586. if (RegionNumRects(current_region)) {
  587. if ((right_shift != 0 || down_shift != 0) &&
  588. !(is_transform && repeat_type == RepeatReflect))
  589. RegionTranslate(current_region, -right_shift * pixmap_width,
  590. -down_shift * pixmap_height);
  591. clipped_regions[m].region = current_region;
  592. clipped_regions[m].block_idx = idx;
  593. m++;
  594. }
  595. else
  596. RegionDestroy(current_region);
  597. RegionUninit(&temp_region);
  598. }
  599. }
  600. if (right_shift != 0 || down_shift != 0)
  601. RegionTranslate(region, -right_shift * pixmap_width,
  602. -down_shift * pixmap_height);
  603. *n_region = m;
  604. return clipped_regions;
  605. }
  606. glamor_pixmap_clipped_regions *
  607. glamor_compute_clipped_regions(glamor_pixmap_private *priv, RegionPtr region,
  608. int *n_region, int repeat_type,
  609. int reverse, int upsidedown)
  610. {
  611. return _glamor_compute_clipped_regions(priv, region, n_region, repeat_type,
  612. 0, reverse, upsidedown);
  613. }
  614. /* XXX overflow still exist. maybe we need to change to use region32.
  615. * by default. Or just use region32 for repeat cases?
  616. **/
  617. glamor_pixmap_clipped_regions *
  618. glamor_compute_transform_clipped_regions(glamor_pixmap_private *priv,
  619. struct pixman_transform *transform,
  620. RegionPtr region, int *n_region,
  621. int dx, int dy, int repeat_type,
  622. int reverse, int upsidedown)
  623. {
  624. BoxPtr temp_extent;
  625. struct pixman_box32 temp_box;
  626. struct pixman_box16 short_box;
  627. RegionPtr temp_region;
  628. glamor_pixmap_clipped_regions *ret;
  629. temp_region = RegionCreate(NULL, 4);
  630. temp_extent = RegionExtents(region);
  631. DEBUGF("dest region \n");
  632. DEBUGRegionPrint(region);
  633. /* dx/dy may exceed MAX SHORT. we have to use
  634. * a box32 to represent it.*/
  635. temp_box.x1 = temp_extent->x1 + dx;
  636. temp_box.x2 = temp_extent->x2 + dx;
  637. temp_box.y1 = temp_extent->y1 + dy;
  638. temp_box.y2 = temp_extent->y2 + dy;
  639. DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
  640. temp_box.y2);
  641. if (transform)
  642. glamor_get_transform_extent_from_box(&temp_box, transform);
  643. if (repeat_type == RepeatNone) {
  644. if (temp_box.x1 < 0)
  645. temp_box.x1 = 0;
  646. if (temp_box.y1 < 0)
  647. temp_box.y1 = 0;
  648. temp_box.x2 = MIN(temp_box.x2, priv->base.pixmap->drawable.width);
  649. temp_box.y2 = MIN(temp_box.y2, priv->base.pixmap->drawable.height);
  650. }
  651. /* Now copy back the box32 to a box16 box. */
  652. short_box.x1 = temp_box.x1;
  653. short_box.y1 = temp_box.y1;
  654. short_box.x2 = temp_box.x2;
  655. short_box.y2 = temp_box.y2;
  656. RegionInitBoxes(temp_region, &short_box, 1);
  657. DEBUGF("copy to temp source region \n");
  658. DEBUGRegionPrint(temp_region);
  659. ret = _glamor_compute_clipped_regions(priv,
  660. temp_region,
  661. n_region,
  662. repeat_type, 1, reverse, upsidedown);
  663. DEBUGF("n_regions = %d \n", *n_region);
  664. RegionDestroy(temp_region);
  665. return ret;
  666. }
  667. /*
  668. * As transform and repeatpad mode.
  669. * We may get a clipped result which in multipe regions.
  670. * It's not easy to do a 2nd round clipping just as we do
  671. * without transform/repeatPad. As it's not easy to reverse
  672. * the 2nd round clipping result with a transform/repeatPad mode,
  673. * or even impossible for some transformation.
  674. *
  675. * So we have to merge the fragmental region into one region
  676. * if the clipped result cross the region boundary.
  677. */
  678. static void
  679. glamor_merge_clipped_regions(glamor_pixmap_private *pixmap_priv,
  680. int repeat_type,
  681. glamor_pixmap_clipped_regions *clipped_regions,
  682. int *n_regions, int *need_clean_fbo)
  683. {
  684. BoxPtr temp_extent;
  685. BoxRec temp_box, copy_box;
  686. RegionPtr temp_region;
  687. glamor_pixmap_private *temp_priv;
  688. PixmapPtr temp_pixmap;
  689. int overlap;
  690. int i;
  691. int pixmap_width, pixmap_height;
  692. glamor_pixmap_private_large_t *priv;
  693. priv = &pixmap_priv->large;
  694. pixmap_width = priv->base.pixmap->drawable.width;
  695. pixmap_height = priv->base.pixmap->drawable.height;
  696. temp_region = RegionCreate(NULL, 4);
  697. for (i = 0; i < *n_regions; i++) {
  698. DEBUGF("Region %d:\n", i);
  699. DEBUGRegionPrint(clipped_regions[i].region);
  700. RegionAppend(temp_region, clipped_regions[i].region);
  701. }
  702. RegionValidate(temp_region, &overlap);
  703. DEBUGF("temp region: \n");
  704. DEBUGRegionPrint(temp_region);
  705. temp_extent = RegionExtents(temp_region);
  706. temp_box = *temp_extent;
  707. DEBUGF("need copy region: \n");
  708. DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
  709. temp_box.y2);
  710. temp_pixmap =
  711. glamor_create_pixmap(priv->base.pixmap->drawable.pScreen,
  712. temp_box.x2 - temp_box.x1,
  713. temp_box.y2 - temp_box.y1,
  714. priv->base.pixmap->drawable.depth,
  715. GLAMOR_CREATE_PIXMAP_FIXUP);
  716. if (temp_pixmap == NULL) {
  717. assert(0);
  718. return;
  719. }
  720. temp_priv = glamor_get_pixmap_private(temp_pixmap);
  721. assert(temp_priv->type != GLAMOR_TEXTURE_LARGE);
  722. priv->box = temp_box;
  723. if (temp_extent->x1 >= 0 && temp_extent->x2 <= pixmap_width
  724. && temp_extent->y1 >= 0 && temp_extent->y2 <= pixmap_height) {
  725. int dx, dy;
  726. copy_box.x1 = 0;
  727. copy_box.y1 = 0;
  728. copy_box.x2 = temp_extent->x2 - temp_extent->x1;
  729. copy_box.y2 = temp_extent->y2 - temp_extent->y1;
  730. dx = temp_extent->x1;
  731. dy = temp_extent->y1;
  732. glamor_copy_n_to_n(&priv->base.pixmap->drawable,
  733. &temp_pixmap->drawable,
  734. NULL, &copy_box, 1, dx, dy, 0, 0, 0, NULL);
  735. // glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
  736. // temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00);
  737. }
  738. else {
  739. for (i = 0; i < *n_regions; i++) {
  740. BoxPtr box;
  741. int nbox;
  742. box = REGION_RECTS(clipped_regions[i].region);
  743. nbox = REGION_NUM_RECTS(clipped_regions[i].region);
  744. while (nbox--) {
  745. int dx, dy, c, d;
  746. DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n",
  747. box->x1, box->y1, box->x2, box->y2);
  748. modulus(box->x1, pixmap_width, c);
  749. dx = c - (box->x1 - temp_box.x1);
  750. copy_box.x1 = box->x1 - temp_box.x1;
  751. copy_box.x2 = box->x2 - temp_box.x1;
  752. modulus(box->y1, pixmap_height, d);
  753. dy = d - (box->y1 - temp_box.y1);
  754. copy_box.y1 = box->y1 - temp_box.y1;
  755. copy_box.y2 = box->y2 - temp_box.y1;
  756. DEBUGF("copying box %d %d %d %d, dx %d dy %d\n",
  757. copy_box.x1, copy_box.y1, copy_box.x2,
  758. copy_box.y2, dx, dy);
  759. glamor_copy_n_to_n(&priv->base.pixmap->drawable,
  760. &temp_pixmap->drawable,
  761. NULL, &copy_box, 1, dx, dy, 0, 0, 0, NULL);
  762. box++;
  763. }
  764. }
  765. //glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
  766. // temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff);
  767. }
  768. /* The first region will be released at caller side. */
  769. for (i = 1; i < *n_regions; i++)
  770. RegionDestroy(clipped_regions[i].region);
  771. RegionDestroy(temp_region);
  772. priv->box = temp_box;
  773. priv->base.fbo = glamor_pixmap_detach_fbo(temp_priv);
  774. DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n",
  775. priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2);
  776. glamor_destroy_pixmap(temp_pixmap);
  777. *need_clean_fbo = 1;
  778. *n_regions = 1;
  779. }
  780. /**
  781. * Given an expected transformed block width and block height,
  782. *
  783. * This function calculate a new block width and height which
  784. * guarantee the transform result will not exceed the given
  785. * block width and height.
  786. *
  787. * For large block width and height (> 2048), we choose a
  788. * smaller new width and height and to reduce the cross region
  789. * boundary and can avoid some overhead.
  790. *
  791. **/
  792. Bool
  793. glamor_get_transform_block_size(struct pixman_transform *transform,
  794. int block_w, int block_h,
  795. int *transformed_block_w,
  796. int *transformed_block_h)
  797. {
  798. double a, b, c, d, e, f, g, h;
  799. double scale;
  800. int width, height;
  801. a = pixman_fixed_to_double(transform->matrix[0][0]);
  802. b = pixman_fixed_to_double(transform->matrix[0][1]);
  803. c = pixman_fixed_to_double(transform->matrix[1][0]);
  804. d = pixman_fixed_to_double(transform->matrix[1][1]);
  805. scale = pixman_fixed_to_double(transform->matrix[2][2]);
  806. if (block_w > 2048) {
  807. /* For large block size, we shrink it to smaller box,
  808. * thus latter we may get less cross boundary regions and
  809. * thus can avoid some extra copy.
  810. *
  811. **/
  812. width = block_w / 4;
  813. height = block_h / 4;
  814. }
  815. else {
  816. width = block_w - 2;
  817. height = block_h - 2;
  818. }
  819. e = a + b;
  820. f = c + d;
  821. g = a - b;
  822. h = c - d;
  823. e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g)));
  824. f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h)));
  825. *transformed_block_w = MIN(e, f) - 1;
  826. *transformed_block_h = *transformed_block_w;
  827. if (*transformed_block_w <= 0 || *transformed_block_h <= 0)
  828. return FALSE;
  829. DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h,
  830. *transformed_block_w, *transformed_block_h);
  831. return TRUE;
  832. }
  833. #define VECTOR_FROM_POINT(p, x, y) \
  834. p.v[0] = x; \
  835. p.v[1] = y; \
  836. p.v[2] = 1.0;
  837. void
  838. glamor_get_transform_extent_from_box(struct pixman_box32 *box,
  839. struct pixman_transform *transform)
  840. {
  841. struct pixman_f_vector p0, p1, p2, p3;
  842. float min_x, min_y, max_x, max_y;
  843. struct pixman_f_transform ftransform;
  844. VECTOR_FROM_POINT(p0, box->x1, box->y1)
  845. VECTOR_FROM_POINT(p1, box->x2, box->y1)
  846. VECTOR_FROM_POINT(p2, box->x2, box->y2)
  847. VECTOR_FROM_POINT(p3, box->x1, box->y2)
  848. pixman_f_transform_from_pixman_transform(&ftransform, transform);
  849. pixman_f_transform_point(&ftransform, &p0);
  850. pixman_f_transform_point(&ftransform, &p1);
  851. pixman_f_transform_point(&ftransform, &p2);
  852. pixman_f_transform_point(&ftransform, &p3);
  853. min_x = MIN(p0.v[0], p1.v[0]);
  854. min_x = MIN(min_x, p2.v[0]);
  855. min_x = MIN(min_x, p3.v[0]);
  856. min_y = MIN(p0.v[1], p1.v[1]);
  857. min_y = MIN(min_y, p2.v[1]);
  858. min_y = MIN(min_y, p3.v[1]);
  859. max_x = MAX(p0.v[0], p1.v[0]);
  860. max_x = MAX(max_x, p2.v[0]);
  861. max_x = MAX(max_x, p3.v[0]);
  862. max_y = MAX(p0.v[1], p1.v[1]);
  863. max_y = MAX(max_y, p2.v[1]);
  864. max_y = MAX(max_y, p3.v[1]);
  865. box->x1 = floor(min_x) - 1;
  866. box->y1 = floor(min_y) - 1;
  867. box->x2 = ceil(max_x) + 1;
  868. box->y2 = ceil(max_y) + 1;
  869. }
  870. static void
  871. _glamor_process_transformed_clipped_region(glamor_pixmap_private *priv,
  872. int repeat_type,
  873. glamor_pixmap_clipped_regions *
  874. clipped_regions, int *n_regions,
  875. int *need_clean_fbo)
  876. {
  877. int shift_x, shift_y;
  878. if (*n_regions != 1) {
  879. /* Merge all source regions into one region. */
  880. glamor_merge_clipped_regions(priv, repeat_type,
  881. clipped_regions, n_regions,
  882. need_clean_fbo);
  883. }
  884. else {
  885. SET_PIXMAP_FBO_CURRENT(priv, clipped_regions[0].block_idx);
  886. if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) {
  887. /* The required source areas are in one region,
  888. * we need to shift the corresponding box's coords to proper position,
  889. * thus we can calculate the relative coords correctly.*/
  890. BoxPtr temp_box;
  891. int rem;
  892. temp_box = RegionExtents(clipped_regions[0].region);
  893. modulus(temp_box->x1, priv->base.pixmap->drawable.width, rem);
  894. shift_x = (temp_box->x1 - rem) / priv->base.pixmap->drawable.width;
  895. modulus(temp_box->y1, priv->base.pixmap->drawable.height, rem);
  896. shift_y = (temp_box->y1 - rem) / priv->base.pixmap->drawable.height;
  897. if (shift_x != 0) {
  898. priv->large.box.x1 +=
  899. shift_x * priv->base.pixmap->drawable.width;
  900. priv->large.box.x2 +=
  901. shift_x * priv->base.pixmap->drawable.width;
  902. }
  903. if (shift_y != 0) {
  904. priv->large.box.y1 +=
  905. shift_y * priv->base.pixmap->drawable.height;
  906. priv->large.box.y2 +=
  907. shift_y * priv->base.pixmap->drawable.height;
  908. }
  909. }
  910. }
  911. }
  912. Bool
  913. glamor_composite_largepixmap_region(CARD8 op,
  914. PicturePtr source,
  915. PicturePtr mask,
  916. PicturePtr dest,
  917. glamor_pixmap_private *source_pixmap_priv,
  918. glamor_pixmap_private *mask_pixmap_priv,
  919. glamor_pixmap_private *dest_pixmap_priv,
  920. RegionPtr region, Bool force_clip,
  921. INT16 x_source,
  922. INT16 y_source,
  923. INT16 x_mask,
  924. INT16 y_mask,
  925. INT16 x_dest, INT16 y_dest,
  926. CARD16 width, CARD16 height)
  927. {
  928. glamor_pixmap_clipped_regions *clipped_dest_regions;
  929. glamor_pixmap_clipped_regions *clipped_source_regions;
  930. glamor_pixmap_clipped_regions *clipped_mask_regions;
  931. int n_dest_regions;
  932. int n_mask_regions;
  933. int n_source_regions;
  934. int i, j, k;
  935. int need_clean_source_fbo = 0;
  936. int need_clean_mask_fbo = 0;
  937. int is_normal_source_fbo = 0;
  938. int is_normal_mask_fbo = 0;
  939. int fixed_block_width, fixed_block_height;
  940. int null_source, null_mask;
  941. glamor_pixmap_private *need_free_source_pixmap_priv = NULL;
  942. glamor_pixmap_private *need_free_mask_pixmap_priv = NULL;
  943. int source_repeat_type = 0, mask_repeat_type = 0;
  944. int ok = TRUE;
  945. if (source->repeat)
  946. source_repeat_type = source->repeatType;
  947. else
  948. source_repeat_type = RepeatNone;
  949. if (mask && mask->repeat)
  950. mask_repeat_type = mask->repeatType;
  951. else
  952. mask_repeat_type = RepeatNone;
  953. fixed_block_width = dest_pixmap_priv->large.block_w;
  954. fixed_block_height = dest_pixmap_priv->large.block_h;
  955. /* If we got an totally out-of-box region for a source or mask
  956. * region without repeat, we need to set it as null_source and
  957. * give it a solid color (0,0,0,0). */
  958. null_source = 0;
  959. null_mask = 0;
  960. RegionTranslate(region, -dest->pDrawable->x, -dest->pDrawable->y);
  961. /* need to transform the dest region to the correct sourcei/mask region.
  962. * it's a little complex, as one single edge of the
  963. * target region may be transformed to cross a block boundary of the
  964. * source or mask. Then it's impossible to handle it as usual way.
  965. * We may have to split the original dest region to smaller region, and
  966. * make sure each region's transformed region can fit into one texture,
  967. * and then continue this loop again, and each time when a transformed region
  968. * cross the bound, we need to copy it to a single pixmap and do the composition
  969. * with the new pixmap. If the transformed region doesn't cross a source/mask's
  970. * boundary then we don't need to copy.
  971. *
  972. */
  973. if (source_pixmap_priv
  974. && source->transform
  975. && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  976. int source_transformed_block_width, source_transformed_block_height;
  977. if (!glamor_get_transform_block_size(source->transform,
  978. source_pixmap_priv->large.block_w,
  979. source_pixmap_priv->large.block_h,
  980. &source_transformed_block_width,
  981. &source_transformed_block_height))
  982. {
  983. DEBUGF("source block size less than 1, fallback.\n");
  984. RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
  985. return FALSE;
  986. }
  987. fixed_block_width =
  988. min(fixed_block_width, source_transformed_block_width);
  989. fixed_block_height =
  990. min(fixed_block_height, source_transformed_block_height);
  991. DEBUGF("new source block size %d x %d \n", fixed_block_width,
  992. fixed_block_height);
  993. }
  994. if (mask_pixmap_priv
  995. && mask->transform && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  996. int mask_transformed_block_width, mask_transformed_block_height;
  997. if (!glamor_get_transform_block_size(mask->transform,
  998. mask_pixmap_priv->large.block_w,
  999. mask_pixmap_priv->large.block_h,
  1000. &mask_transformed_block_width,
  1001. &mask_transformed_block_height)) {
  1002. DEBUGF("mask block size less than 1, fallback.\n");
  1003. RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
  1004. return FALSE;
  1005. }
  1006. fixed_block_width =
  1007. min(fixed_block_width, mask_transformed_block_width);
  1008. fixed_block_height =
  1009. min(fixed_block_height, mask_transformed_block_height);
  1010. DEBUGF("new mask block size %d x %d \n", fixed_block_width,
  1011. fixed_block_height);
  1012. }
  1013. /*compute the correct block width and height whose transformed source/mask
  1014. *region can fit into one texture.*/
  1015. if (force_clip || fixed_block_width < dest_pixmap_priv->large.block_w
  1016. || fixed_block_height < dest_pixmap_priv->large.block_h)
  1017. clipped_dest_regions =
  1018. glamor_compute_clipped_regions_ext(dest_pixmap_priv, region,
  1019. &n_dest_regions,
  1020. fixed_block_width,
  1021. fixed_block_height, 0, 0);
  1022. else
  1023. clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap_priv,
  1024. region,
  1025. &n_dest_regions,
  1026. 0, 0, 0);
  1027. DEBUGF("dest clipped result %d region: \n", n_dest_regions);
  1028. if (source_pixmap_priv
  1029. && (source_pixmap_priv == dest_pixmap_priv ||
  1030. source_pixmap_priv == mask_pixmap_priv)
  1031. && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  1032. /* XXX self-copy... */
  1033. need_free_source_pixmap_priv = source_pixmap_priv;
  1034. source_pixmap_priv = malloc(sizeof(*source_pixmap_priv));
  1035. *source_pixmap_priv = *need_free_source_pixmap_priv;
  1036. need_free_source_pixmap_priv = source_pixmap_priv;
  1037. }
  1038. assert(mask_pixmap_priv != dest_pixmap_priv);
  1039. for (i = 0; i < n_dest_regions; i++) {
  1040. DEBUGF("dest region %d idx %d\n", i,
  1041. clipped_dest_regions[i].block_idx);
  1042. DEBUGRegionPrint(clipped_dest_regions[i].region);
  1043. SET_PIXMAP_FBO_CURRENT(dest_pixmap_priv,
  1044. clipped_dest_regions[i].block_idx);
  1045. if (source_pixmap_priv &&
  1046. source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  1047. if (!source->transform && source_repeat_type != RepeatPad) {
  1048. RegionTranslate(clipped_dest_regions[i].region,
  1049. x_source - x_dest, y_source - y_dest);
  1050. clipped_source_regions =
  1051. glamor_compute_clipped_regions(source_pixmap_priv,
  1052. clipped_dest_regions[i].
  1053. region, &n_source_regions,
  1054. source_repeat_type, 0, 0);
  1055. is_normal_source_fbo = 1;
  1056. }
  1057. else {
  1058. clipped_source_regions =
  1059. glamor_compute_transform_clipped_regions(source_pixmap_priv,
  1060. source->transform,
  1061. clipped_dest_regions
  1062. [i].region,
  1063. &n_source_regions,
  1064. x_source - x_dest,
  1065. y_source - y_dest,
  1066. source_repeat_type,
  1067. 0, 0);
  1068. is_normal_source_fbo = 0;
  1069. if (n_source_regions == 0) {
  1070. /* Pad the out-of-box region to (0,0,0,0). */
  1071. null_source = 1;
  1072. n_source_regions = 1;
  1073. }
  1074. else
  1075. _glamor_process_transformed_clipped_region
  1076. (source_pixmap_priv, source_repeat_type,
  1077. clipped_source_regions, &n_source_regions,
  1078. &need_clean_source_fbo);
  1079. }
  1080. DEBUGF("source clipped result %d region: \n", n_source_regions);
  1081. for (j = 0; j < n_source_regions; j++) {
  1082. if (is_normal_source_fbo)
  1083. SET_PIXMAP_FBO_CURRENT(source_pixmap_priv,
  1084. clipped_source_regions[j].block_idx);
  1085. if (mask_pixmap_priv &&
  1086. mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  1087. if (is_normal_mask_fbo && is_normal_source_fbo) {
  1088. /* both mask and source are normal fbo box without transform or repeatpad.
  1089. * The region is clipped against source and then we clip it against mask here.*/
  1090. DEBUGF("source region %d idx %d\n", j,
  1091. clipped_source_regions[j].block_idx);
  1092. DEBUGRegionPrint(clipped_source_regions[j].region);
  1093. RegionTranslate(clipped_source_regions[j].region,
  1094. -x_source + x_mask, -y_source + y_mask);
  1095. clipped_mask_regions =
  1096. glamor_compute_clipped_regions(mask_pixmap_priv,
  1097. clipped_source_regions
  1098. [j].region,
  1099. &n_mask_regions,
  1100. mask_repeat_type, 0,
  1101. 0);
  1102. is_normal_mask_fbo = 1;
  1103. }
  1104. else if (is_normal_mask_fbo && !is_normal_source_fbo) {
  1105. assert(n_source_regions == 1);
  1106. /* The source fbo is not a normal fbo box, it has transform or repeatpad.
  1107. * the valid clip region should be the clip dest region rather than the
  1108. * clip source region.*/
  1109. RegionTranslate(clipped_dest_regions[i].region,
  1110. -x_dest + x_mask, -y_dest + y_mask);
  1111. clipped_mask_regions =
  1112. glamor_compute_clipped_regions(mask_pixmap_priv,
  1113. clipped_dest_regions
  1114. [i].region,
  1115. &n_mask_regions,
  1116. mask_repeat_type, 0,
  1117. 0);
  1118. is_normal_mask_fbo = 1;
  1119. }
  1120. else {
  1121. /* This mask region has transform or repeatpad, we need clip it agains the previous
  1122. * valid region rather than the mask region. */
  1123. if (!is_normal_source_fbo)
  1124. clipped_mask_regions =
  1125. glamor_compute_transform_clipped_regions
  1126. (mask_pixmap_priv, mask->transform,
  1127. clipped_dest_regions[i].region,
  1128. &n_mask_regions, x_mask - x_dest,
  1129. y_mask - y_dest, mask_repeat_type, 0, 0);
  1130. else
  1131. clipped_mask_regions =
  1132. glamor_compute_transform_clipped_regions
  1133. (mask_pixmap_priv, mask->transform,
  1134. clipped_source_regions[j].region,
  1135. &n_mask_regions, x_mask - x_source,
  1136. y_mask - y_source, mask_repeat_type, 0, 0);
  1137. is_normal_mask_fbo = 0;
  1138. if (n_mask_regions == 0) {
  1139. /* Pad the out-of-box region to (0,0,0,0). */
  1140. null_mask = 1;
  1141. n_mask_regions = 1;
  1142. }
  1143. else
  1144. _glamor_process_transformed_clipped_region
  1145. (mask_pixmap_priv, mask_repeat_type,
  1146. clipped_mask_regions, &n_mask_regions,
  1147. &need_clean_mask_fbo);
  1148. }
  1149. DEBUGF("mask clipped result %d region: \n", n_mask_regions);
  1150. #define COMPOSITE_REGION(region) do { \
  1151. if (!glamor_composite_clipped_region(op, \
  1152. null_source ? NULL : source, \
  1153. null_mask ? NULL : mask, dest, \
  1154. null_source ? NULL : source_pixmap_priv, \
  1155. null_mask ? NULL : mask_pixmap_priv, \
  1156. dest_pixmap_priv, region, \
  1157. x_source, y_source, x_mask, y_mask, \
  1158. x_dest, y_dest)) { \
  1159. assert(0); \
  1160. } \
  1161. } while(0)
  1162. for (k = 0; k < n_mask_regions; k++) {
  1163. DEBUGF("mask region %d idx %d\n", k,
  1164. clipped_mask_regions[k].block_idx);
  1165. DEBUGRegionPrint(clipped_mask_regions[k].region);
  1166. if (is_normal_mask_fbo) {
  1167. SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
  1168. clipped_mask_regions[k].
  1169. block_idx);
  1170. DEBUGF("mask fbo off %d %d \n",
  1171. mask_pixmap_priv->large.box.x1,
  1172. mask_pixmap_priv->large.box.y1);
  1173. DEBUGF("start composite mask hasn't transform.\n");
  1174. RegionTranslate(clipped_mask_regions[k].region,
  1175. x_dest - x_mask +
  1176. dest->pDrawable->x,
  1177. y_dest - y_mask +
  1178. dest->pDrawable->y);
  1179. COMPOSITE_REGION(clipped_mask_regions[k].region);
  1180. }
  1181. else if (!is_normal_mask_fbo && !is_normal_source_fbo) {
  1182. DEBUGF
  1183. ("start composite both mask and source have transform.\n");
  1184. RegionTranslate(clipped_dest_regions[i].region,
  1185. dest->pDrawable->x,
  1186. dest->pDrawable->y);
  1187. COMPOSITE_REGION(clipped_dest_regions[i].region);
  1188. }
  1189. else {
  1190. DEBUGF
  1191. ("start composite only mask has transform.\n");
  1192. RegionTranslate(clipped_source_regions[j].region,
  1193. x_dest - x_source +
  1194. dest->pDrawable->x,
  1195. y_dest - y_source +
  1196. dest->pDrawable->y);
  1197. COMPOSITE_REGION(clipped_source_regions[j].region);
  1198. }
  1199. RegionDestroy(clipped_mask_regions[k].region);
  1200. }
  1201. free(clipped_mask_regions);
  1202. if (null_mask)
  1203. null_mask = 0;
  1204. if (need_clean_mask_fbo) {
  1205. assert(is_normal_mask_fbo == 0);
  1206. glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
  1207. mask_pixmap_priv->base.fbo = NULL;
  1208. need_clean_mask_fbo = 0;
  1209. }
  1210. }
  1211. else {
  1212. if (is_normal_source_fbo) {
  1213. RegionTranslate(clipped_source_regions[j].region,
  1214. -x_source + x_dest + dest->pDrawable->x,
  1215. -y_source + y_dest +
  1216. dest->pDrawable->y);
  1217. COMPOSITE_REGION(clipped_source_regions[j].region);
  1218. }
  1219. else {
  1220. /* Source has transform or repeatPad. dest regions is the right
  1221. * region to do the composite. */
  1222. RegionTranslate(clipped_dest_regions[i].region,
  1223. dest->pDrawable->x, dest->pDrawable->y);
  1224. COMPOSITE_REGION(clipped_dest_regions[i].region);
  1225. }
  1226. }
  1227. if (clipped_source_regions && clipped_source_regions[j].region)
  1228. RegionDestroy(clipped_source_regions[j].region);
  1229. }
  1230. free(clipped_source_regions);
  1231. if (null_source)
  1232. null_source = 0;
  1233. if (need_clean_source_fbo) {
  1234. assert(is_normal_source_fbo == 0);
  1235. glamor_destroy_fbo(source_pixmap_priv->base.fbo);
  1236. source_pixmap_priv->base.fbo = NULL;
  1237. need_clean_source_fbo = 0;
  1238. }
  1239. }
  1240. else {
  1241. if (mask_pixmap_priv &&
  1242. mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
  1243. if (!mask->transform && mask_repeat_type != RepeatPad) {
  1244. RegionTranslate(clipped_dest_regions[i].region,
  1245. x_mask - x_dest, y_mask - y_dest);
  1246. clipped_mask_regions =
  1247. glamor_compute_clipped_regions(mask_pixmap_priv,
  1248. clipped_dest_regions[i].
  1249. region, &n_mask_regions,
  1250. mask_repeat_type, 0, 0);
  1251. is_normal_mask_fbo = 1;
  1252. }
  1253. else {
  1254. clipped_mask_regions =
  1255. glamor_compute_transform_clipped_regions
  1256. (mask_pixmap_priv, mask->transform,
  1257. clipped_dest_regions[i].region, &n_mask_regions,
  1258. x_mask - x_dest, y_mask - y_dest, mask_repeat_type, 0,
  1259. 0);
  1260. is_normal_mask_fbo = 0;
  1261. if (n_mask_regions == 0) {
  1262. /* Pad the out-of-box region to (0,0,0,0). */
  1263. null_mask = 1;
  1264. n_mask_regions = 1;
  1265. }
  1266. else
  1267. _glamor_process_transformed_clipped_region
  1268. (mask_pixmap_priv, mask_repeat_type,
  1269. clipped_mask_regions, &n_mask_regions,
  1270. &need_clean_mask_fbo);
  1271. }
  1272. for (k = 0; k < n_mask_regions; k++) {
  1273. DEBUGF("mask region %d idx %d\n", k,
  1274. clipped_mask_regions[k].block_idx);
  1275. DEBUGRegionPrint(clipped_mask_regions[k].region);
  1276. if (is_normal_mask_fbo) {
  1277. SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
  1278. clipped_mask_regions[k].
  1279. block_idx);
  1280. RegionTranslate(clipped_mask_regions[k].region,
  1281. x_dest - x_mask + dest->pDrawable->x,
  1282. y_dest - y_mask + dest->pDrawable->y);
  1283. COMPOSITE_REGION(clipped_mask_regions[k].region);
  1284. }
  1285. else {
  1286. RegionTranslate(clipped_dest_regions[i].region,
  1287. dest->pDrawable->x, dest->pDrawable->y);
  1288. COMPOSITE_REGION(clipped_dest_regions[i].region);
  1289. }
  1290. RegionDestroy(clipped_mask_regions[k].region);
  1291. }
  1292. free(clipped_mask_regions);
  1293. if (null_mask)
  1294. null_mask = 0;
  1295. if (need_clean_mask_fbo) {
  1296. glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
  1297. mask_pixmap_priv->base.fbo = NULL;
  1298. need_clean_mask_fbo = 0;
  1299. }
  1300. }
  1301. else {
  1302. RegionTranslate(clipped_dest_regions[i].region,
  1303. dest->pDrawable->x, dest->pDrawable->y);
  1304. COMPOSITE_REGION(clipped_dest_regions[i].region);
  1305. }
  1306. }
  1307. RegionDestroy(clipped_dest_regions[i].region);
  1308. }
  1309. free(clipped_dest_regions);
  1310. free(need_free_source_pixmap_priv);
  1311. free(need_free_mask_pixmap_priv);
  1312. ok = TRUE;
  1313. return ok;
  1314. }