• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright Samsung Electronics Co.,LTD.
3  * Copyright (C) 2016 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 <log/log.h>
19 
20 #include <hardware/exynos/acryl.h>
21 #include <hardware/hwcomposer2.h>
22 
23 #include "acrylic_internal.h"
24 
AcrylicCanvas(Acrylic * compositor,canvas_type_t type)25 AcrylicCanvas::AcrylicCanvas(Acrylic *compositor, canvas_type_t type)
26     : mCompositor(compositor), mPixFormat(0), mNumBuffers(0), mFence(-1), mAttributes(ATTR_NONE),
27       mSettingFlags(0), mCanvasType(type)
28 {
29     // Initialize the image size to the possible smallest size
30     mImageDimension = compositor->getCapabilities().supportedMinSrcDimension();
31 }
32 
~AcrylicCanvas()33 AcrylicCanvas::~AcrylicCanvas()
34 {
35     setFence(-1);
36 }
37 
canvasTypeName(unsigned int type)38 static const char *canvasTypeName(unsigned int type)
39 {
40     static const char canvas_type_name[2][7] = {"source", "target"};
41 
42     return canvas_type_name[type];
43 }
44 
setImageDimension(int32_t width,int32_t height)45 bool AcrylicCanvas::setImageDimension(int32_t width, int32_t height)
46 {
47     if (((getSettingFlags() & SETTING_DIMENSION) != 0) &&
48             (width == mImageDimension.hori) && (height == mImageDimension.vert))
49         return true;
50 
51     if (!getCompositor()) {
52         ALOGE("Trying to set image dimension to an orphaned layer");
53         return false;
54     }
55 
56     unset(SETTING_DIMENSION);
57 
58     const HW2DCapability &cap = getCompositor()->getCapabilities();
59 
60     hw2d_coord_t minsize, maxsize;
61 
62     if (mCanvasType == CANVAS_SOURCE) {
63         minsize = cap.supportedMinSrcDimension();
64         maxsize = cap.supportedMaxSrcDimension();
65     } else {
66         minsize = cap.supportedMinDstDimension();
67         maxsize = cap.supportedMaxDstDimension();
68     }
69 
70     if ((width < minsize.hori) || (height < minsize.vert) || (width > maxsize.hori) || (height > maxsize.vert)) {
71         ALOGE("Invalid %s image size %dx%d (limit: %dx%d ~ %dx%d )",
72               canvasTypeName(mCanvasType), width, height,
73               minsize.hori, minsize.vert, maxsize.hori, maxsize.vert);
74         return false;
75     }
76 
77     minsize = cap.supportedDimensionAlign();
78     if (!!(width & (minsize.hori - 1)) || !!(height & (minsize.vert - 1))) {
79         ALOGE("%s image size %dx%d violates alignment restriction %dx%d",
80               canvasTypeName(mCanvasType), width, height, minsize.hori, minsize.vert);
81         return false;
82     }
83 
84     mImageDimension.hori = static_cast<int16_t>(width);
85     mImageDimension.vert = static_cast<int16_t>(height);
86 
87     set(SETTING_DIMENSION | SETTING_DIMENSION_MODIFIED);
88 
89     ALOGD_TEST("Configured dimension: %dx%d (type: %s)", width, height, canvasTypeName(mCanvasType));
90 
91     return true;
92 }
93 
setImageBuffer(int a,int r,int g,int b,uint32_t attr)94 bool AcrylicCanvas::setImageBuffer(int a, int r, int g, int b, uint32_t attr)
95 {
96     if (!getCompositor()) {
97         ALOGE("Trying to set buffer to an orphaned layer");
98         return false;
99     }
100 
101     const HW2DCapability &cap = getCompositor()->getCapabilities();
102 
103     if (((mCanvasType == CANVAS_SOURCE) && !cap.isFeatureSupported(HW2DCapability::FEATURE_SOLIDCOLOR)) ||
104         (mCanvasType == CANVAS_TARGET)) {
105         ALOGE("SolidColor is not supported for %s", canvasTypeName(mCanvasType));
106         return false;
107     }
108 
109     setFence(-1);
110     mMemoryType = MT_EMPTY;
111     mNumBuffers = 0;
112 
113     mAttributes = (attr & ATTR_ALL_MASK) | ATTR_SOLIDCOLOR;
114 
115     set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
116 
117     mSolidColor  = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF));
118 
119     return true;
120 }
121 
setImageBuffer(int fd[MAX_HW2D_PLANES],size_t len[MAX_HW2D_PLANES],off_t offset[MAX_HW2D_PLANES],int num_buffers,int fence,uint32_t attr)122 bool AcrylicCanvas::setImageBuffer(int fd[MAX_HW2D_PLANES], size_t len[MAX_HW2D_PLANES], off_t offset[MAX_HW2D_PLANES],
123                                    int num_buffers, int fence, uint32_t attr)
124 {
125     if ((attr & ATTR_OTF) != 0)
126         return setImageOTFBuffer(attr);
127 
128     if (!getCompositor()) {
129         ALOGE("Trying to set buffer to an orphaned layer");
130         return false;
131     }
132 
133     const HW2DCapability &cap = getCompositor()->getCapabilities();
134     unsigned long alignmask = static_cast<unsigned long>(cap.supportedBaseAlign()) - 1;
135 
136     if (num_buffers > MAX_HW2D_PLANES) {
137         ALOGE("Too many buffers %d are set passed to setImageBuffer(dmabuf)", num_buffers);
138         return false;
139     }
140 
141     for (int i = 0; i < num_buffers; i++) {
142         if ((offset[i] < 0) || (static_cast<size_t>(offset[i]) >= len[i])) {
143             ALOGE("Too large offset %jd for length %zu of buffer[%d]",
144                   static_cast<intmax_t>(offset[i]), len[i], i);
145             return false;
146         }
147 
148         if ((offset[i] & alignmask) != 0) {
149             ALOGE("Alignment of offset %#lx of buffer[%d] violates the alignment of %#lx",
150                     offset[i], i, alignmask + 1);
151             return false;
152         }
153     }
154 
155     for (int i = 0; i < num_buffers; i++) {
156         m.mBufferFd[i] = fd[i];
157         mBufferLength[i] = len[i];
158         mBufferOffset[i] = offset[i];
159         ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %jd (type: %s)", i,
160                    m.mBufferFd[i], mBufferLength[i], static_cast<intmax_t>(mBufferOffset[i]),
161                    canvasTypeName(mCanvasType));
162     }
163 
164     ALOGE_IF((attr & ~ATTR_ALL_MASK) != 0,
165              "Configured unsupported attribute %#x to setImageBuffer(dmabuf))", attr);
166 
167     setFence(fence);
168     mMemoryType = MT_DMABUF;
169     mNumBuffers = num_buffers;
170 
171     mAttributes = attr & ATTR_ALL_MASK;
172     ALOGD_TEST("Configured buffer: fence %d, type %d, count %d, attr %#x (type: %s)",
173                mFence, mMemoryType, mNumBuffers, mAttributes, canvasTypeName(mCanvasType));
174 
175     set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
176 
177     return true;
178 }
179 
setImageBuffer(void * addr[MAX_HW2D_PLANES],size_t len[MAX_HW2D_PLANES],int num_buffers,uint32_t attr)180 bool AcrylicCanvas::setImageBuffer(void *addr[MAX_HW2D_PLANES], size_t len[MAX_HW2D_PLANES],
181                                    int num_buffers, uint32_t attr)
182 {
183     if ((attr & ATTR_OTF) != 0)
184         return setImageOTFBuffer(attr);
185 
186     if (!getCompositor()) {
187         ALOGE("Trying to set buffer to an orphaned layer");
188         return false;
189     }
190 
191     const HW2DCapability &cap = getCompositor()->getCapabilities();
192     unsigned long alignmask = static_cast<unsigned long>(cap.supportedBaseAlign()) - 1;
193 
194     if (num_buffers > MAX_HW2D_PLANES) {
195         ALOGE("Too many buffers %d are set passed to setImageBuffer(userptr)", num_buffers);
196         return false;
197     }
198 
199     for (int i = 0; i < num_buffers; i++) {
200         if ((reinterpret_cast<unsigned long>(addr[i]) & alignmask) != 0) {
201             ALOGE("Alignment of address %p of buffer[%d] violates the alignment of %#lx",
202                     addr[i], i, alignmask + 1);
203             return false;
204         }
205     }
206 
207     for (int i = 0; i < num_buffers; i++) {
208         m.mBufferAddr[i] = addr[i];
209         mBufferLength[i] = len[i];
210         mBufferOffset[i] = 0;
211         ALOGD_TEST("Configured buffer[%d]: addr %p, len %zu, offset %u (type: %s)",
212                    i, m.mBufferAddr[i], mBufferLength[i], mBufferOffset[i],
213                    canvasTypeName(mCanvasType));
214     }
215 
216     ALOGE_IF((attr & ~ATTR_ALL_MASK) != 0,
217              "Configured unsupported attribute %#x to setImageBuffer(userptr))", attr);
218 
219     setFence(-1);
220     mMemoryType = MT_USERPTR;
221     mNumBuffers = num_buffers;
222 
223     mAttributes = attr & ATTR_ALL_MASK;
224 
225     ALOGD_TEST("Configured buffer: fence %d, type %d, count %d, attr %#x (type: %s)",
226                mFence, mMemoryType, mNumBuffers, mAttributes, canvasTypeName(mCanvasType));
227 
228     set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
229 
230     return true;
231 }
232 
setImageOTFBuffer(uint32_t attr)233 bool AcrylicCanvas::setImageOTFBuffer(uint32_t attr)
234 {
235     if (!getCompositor()) {
236         ALOGE("Trying to set buffer to an orphaned layer");
237         return false;
238     }
239 
240     const HW2DCapability &cap = getCompositor()->getCapabilities();
241 
242     if (((mCanvasType == CANVAS_SOURCE) && !cap.isFeatureSupported(HW2DCapability::FEATURE_OTF_READ)) ||
243         ((mCanvasType == CANVAS_TARGET) && !cap.isFeatureSupported(HW2DCapability::FEATURE_OTF_WRITE))) {
244         ALOGE("OTF is not supported for %s", canvasTypeName(mCanvasType));
245         return false;
246     }
247 
248     setFence(-1);
249     mMemoryType = MT_EMPTY;
250     mNumBuffers = 0;
251 
252     mAttributes = (attr & ATTR_ALL_MASK) | ATTR_OTF;
253 
254     set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
255 
256     return true;
257 }
258 
setImageType(uint32_t fmt,int dataspace)259 bool AcrylicCanvas::setImageType(uint32_t fmt, int dataspace)
260 {
261     if (((getSettingFlags() & SETTING_TYPE) != 0) &&
262             (mPixFormat == fmt) && (mDataSpace == dataspace))
263         return true;
264 
265     if (!getCompositor()) {
266         ALOGE("Trying to set image type to an orphaned layer");
267         return false;
268     }
269 
270     unset(SETTING_TYPE);
271 
272     const HW2DCapability &cap = getCompositor()->getCapabilities();
273 
274     if (!cap.isFormatSupported(fmt)) {
275         ALOGE("fmt %#x is not supported.", fmt);
276         return false;
277     }
278 
279     if (!cap.isDataspaceSupported(dataspace)) {
280         ALOGE("dataspace %d is not supported.", dataspace);
281         return false;
282     }
283 
284     mPixFormat = fmt;
285     mDataSpace = dataspace;
286 
287     ALOGD_TEST("Configured format %#x and dataspace %#x (type: %s)",
288                mPixFormat, mDataSpace, canvasTypeName(mCanvasType));
289 
290     set(SETTING_TYPE | SETTING_TYPE_MODIFIED);
291 
292     return true;
293 }
294 
setFence(int fence)295 void AcrylicCanvas::setFence(int fence)
296 {
297     if (mFence >= 0)
298         close(mFence);
299 
300     mFence = fence;
301 }
302 
AcrylicLayer(Acrylic * compositor)303 AcrylicLayer::AcrylicLayer(Acrylic *compositor)
304     : AcrylicCanvas(compositor), mTransitData(nullptr), mBlendingMode(HWC_BLENDING_NONE),
305       mTransform(0), mZOrder(0), mMaxLuminance(100), mMinLuminance(0), mPlaneAlpha(255)
306 {
307     // Default settings:
308     // - Bleding mode: SRC_OVER
309     // - Rotaion: 0 degree
310     // - Flip: none
311     // - z-order: 0
312     // - plane alpha: 1 (255)
313     // - master display: [0.0000 nit ~ 100.0000 nit] (SDR)
314     // - target area: full area of the target image
315     mTargetRect.pos = {0, 0};
316     mTargetRect.size = {0, 0};
317 }
318 
~AcrylicLayer()319 AcrylicLayer::~AcrylicLayer()
320 {
321     if (mCompositor)
322         mCompositor->removeLayer(this);
323 }
324 
setCompositMode(uint32_t mode,uint8_t alpha,int z_order)325 bool AcrylicLayer::setCompositMode(uint32_t mode, uint8_t alpha, int z_order)
326 {
327     if (!getCompositor()) {
328         ALOGE("Trying to set compositing mode to an orphaned layer");
329         return false;
330     }
331 
332     const HW2DCapability &cap = getCompositor()->getCapabilities();
333 
334     bool okay = true;
335     switch (mode) {
336         case HWC_BLENDING_NONE:
337         case HWC2_BLEND_MODE_NONE:
338             if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_SRC_COPY))
339                 okay = false;
340             break;
341         case HWC_BLENDING_PREMULT:
342         case HWC2_BLEND_MODE_PREMULTIPLIED:
343             if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_SRC_OVER))
344                 okay = false;
345             break;
346         case HWC_BLENDING_COVERAGE:
347         case HWC2_BLEND_MODE_COVERAGE:
348             if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_NONE))
349                 okay = false;
350             break;
351         default:
352             ALOGE("Unknown bleding mode %#x", mode);
353             return false;
354     }
355 
356     if (!okay) {
357         ALOGE("Unsupported blending mode %#x", mode);
358         return false;
359     }
360 
361     mBlendingMode = mode;
362 
363     mZOrder = z_order;
364     mPlaneAlpha = alpha;
365 
366     ALOGD_TEST("Configured compositing mode: mode %d, z-order %d, alpha %d",
367                mBlendingMode, mZOrder, mPlaneAlpha);
368 
369     return true;
370 }
371 
372 #define ALOGE_RECT(msg, title, rect)   ALOGE(msg ": (%d, %d) -> (%d, %d)", title, (rect).left, (rect).top, (rect).right, (rect).bottom);
373 
setCompositArea(hwc_rect_t & src_area,hwc_rect_t & out_area,uint32_t transform,uint32_t attr)374 bool AcrylicLayer::setCompositArea(hwc_rect_t &src_area, hwc_rect_t &out_area, uint32_t transform, uint32_t attr)
375 {
376     if (!getCompositor()) {
377         ALOGE("Trying to set compositing area to an orphaned layer");
378         return false;
379     }
380 
381     const HW2DCapability &cap = getCompositor()->getCapabilities();
382     hw2d_coord_t limit;
383 
384     // 1. Transform capability check
385     if ((transform & cap.getHWCTransformMask()) != transform) {
386         ALOGE("transform value %#x is not supported: supported transform mask: %#x",
387               transform, cap.getHWCTransformMask());
388         return false;
389     }
390 
391     // 2. Source area verification
392     int32_t val = src_area.left | src_area.top | src_area.right | src_area.bottom;
393     if (val < 0) {
394         ALOGE_RECT("Negative position in the %s area", "source", src_area);
395         return false;
396     }
397 
398     if ((src_area.left >= src_area.right) || (src_area.top >= src_area.bottom)) {
399         ALOGE_RECT("Invalid %s position and area", "source", out_area);
400         return false;
401     }
402 
403     limit = cap.supportedMinSrcDimension();
404     if ((get_width(src_area) < limit.hori) || (get_height(src_area) < limit.vert)) {
405         ALOGE_RECT("Too small %s area", "source", src_area);
406         return false;
407     }
408 
409     limit = getImageDimension();
410     if ((src_area.right > limit.hori) || (src_area.bottom > limit.vert)) {
411         ALOGE_RECT("Too large %s area", "source", src_area);
412         ALOGE("        Image full size: %dx%d", limit.hori, limit.vert);
413         return false;
414     }
415 
416     // 3. Target area verification
417     val = out_area.left | out_area.top | out_area.right | out_area.bottom;
418     if (val != 0) {
419         // The following checks on the target area are deferred to commit()
420         // - if area size is larger than the limit
421         // - if the right/bottom position exceed the limit
422         if (val < 0) {
423             ALOGE_RECT("Negative position in the %s area", "target", out_area);
424             return false;
425         }
426 
427         if ((out_area.left >= out_area.right) || (out_area.top >= out_area.bottom)) {
428             ALOGE_RECT("Invalid %s position and area", "target", out_area);
429             return false;
430         }
431 
432         limit = cap.supportedMinDstDimension();
433         if ((get_width(out_area) < limit.hori) || (get_height(out_area) < limit.vert)) {
434             ALOGE_RECT("too small %s area", "target", out_area);
435             return false;
436         }
437 
438         // 4. Scaling limit verification if target area is specified
439         hw2d_coord_t src_xy, out_xy;
440 
441         src_xy.hori = get_width(src_area);
442         src_xy.vert = get_height(src_area);
443         out_xy.hori = get_width(out_area);
444         out_xy.vert = get_height(out_area);
445 
446         bool scaling_ok = !(attr & ATTR_NORESAMPLING)
447             ? cap.supportedResampling(src_xy, out_xy, transform)
448             : cap.supportedResizing(src_xy, out_xy, transform);
449 
450         if (!scaling_ok) {
451             ALOGE("Unsupported scaling from %dx%d@(%d,%d) --> %dx%d@(%d,%d) with transform %d and attr %#x",
452                     get_width(src_area), get_height(src_area), src_area.left, src_area.top,
453                     get_width(out_area), get_height(out_area), out_area.left, out_area.top, transform, attr);
454             return false;
455         }
456     }
457 
458     mTargetRect.pos.hori = static_cast<int16_t>(out_area.left);
459     mTargetRect.pos.vert = static_cast<int16_t>(out_area.top);
460     mTargetRect.size.hori = static_cast<int16_t>(get_width(out_area));
461     mTargetRect.size.vert = static_cast<int16_t>(get_height(out_area));
462 
463     mImageRect.pos.hori = static_cast<int16_t>(src_area.left);
464     mImageRect.pos.vert = static_cast<int16_t>(src_area.top);
465     mImageRect.size.hori = static_cast<int16_t>(get_width(src_area));
466     mImageRect.size.vert = static_cast<int16_t>(get_height(src_area));
467 
468     mTransform = transform;
469     mCompositAttr = attr & ATTR_ALL_MASK;
470 
471     ALOGD_TEST("Configured area: %dx%d@%dx%d -> %dx%d@%dx%d, transform: %d, attr: %#x",
472                 mImageRect.size.hori, mImageRect.size.vert, mImageRect.pos.hori, mImageRect.pos.vert,
473                 mTargetRect.size.hori, mTargetRect.size.vert, mTargetRect.pos.hori, mTargetRect.pos.vert,
474                 mTransform, mCompositAttr);
475 
476     return true;
477 }
478 
setImageDimension(int32_t width,int32_t height)479 bool AcrylicLayer::setImageDimension(int32_t width, int32_t height)
480 {
481     if (!AcrylicCanvas::setImageDimension(width, height))
482         return false;
483 
484     // NOTE: the crop area should be initialized with the new image size
485     mImageRect.pos = {0, 0};
486     mImageRect.size = getImageDimension();
487 
488     ALOGD_TEST("Reset the image rect to %dx%d@0x0", mImageRect.size.hori, mImageRect.size.vert);
489 
490     return true;
491 }
492 
setMasterDisplayLuminance(uint16_t min,uint16_t max)493 void AcrylicLayer::setMasterDisplayLuminance(uint16_t min, uint16_t max)
494 {
495     if (max < 100) {
496         ALOGE("Too small max display luminance %u.", max);
497     } else {
498         mMaxLuminance = max;
499         mMinLuminance = min;
500     }
501 }
502 
importLayer(AcrylicLayer & other,bool inherit_transform)503 void AcrylicLayer::importLayer(AcrylicLayer &other, bool inherit_transform)
504 {
505     // Data to import
506     // - image size and the image rect
507     // - buffer and its attributes
508     // - acquire fence (the fence of @other should be invalidated)
509     // - pixel format, color space
510     // - geometric transformation if @inherit_transform is true
511     // Data NOT to import
512     // - the target rect
513     // - the blending attribute
514     // - z-order and plane alpha
515     hw2d_coord_t xy = other.getImageDimension();
516     AcrylicCanvas::setImageDimension(xy.hori, xy.vert);
517     setImageType(other.getFormat(), other.getDataspace());
518 
519     uint32_t attr = ATTR_NONE;
520     if (other.isProtected())
521         attr |= ATTR_PROTECTED;
522     if (other.isCompressed())
523         attr |= ATTR_COMPRESSED;
524     if (other.isCompressedWideblk()) attr |= ATTR_COMPRESSED_WIDEBLK;
525 
526     if (other.getBufferType() == MT_DMABUF) {
527         int fd[3];
528         off_t off[3];
529         size_t len[3];
530 
531         for (unsigned int i = 0; i < other.getBufferCount(); i++) {
532             fd[i] = other.getDmabuf(i);
533             off[i] = other.getOffset(i);
534             len[i] = other.getBufferLength(i);
535         }
536 
537         setImageBuffer(fd, len, off, other.getBufferCount(), other.getFence(), attr);
538     } else {
539         void *addr[3];
540         size_t len[3];
541 
542         for (unsigned int i = 0; i < other.getBufferCount(); i++) {
543             addr[i] = other.getUserptr(i);
544             len[i] = other.getBufferLength(i);
545         }
546 
547         setImageBuffer(addr, len, other.getBufferCount(), attr);
548     }
549 
550     other.clearFence();
551     mImageRect = other.mImageRect;
552     if (inherit_transform)
553         mTransform = other.mTransform;
554 }
555