Surface و SurfaceHolder

اشیاء سطحی (Surface objects) به برنامه‌ها این امکان را می‌دهند که تصاویر را برای نمایش روی صفحه نمایش رندر کنند. رابط‌های SurfaceHolder به برنامه‌ها این امکان را می‌دهند که سطوح (surfaces) را ویرایش و کنترل کنند.

سطح

یک سطح ، رابطی برای تولیدکننده است تا بافرها را با مصرف‌کننده مبادله کند.

سطوح نمایشگر معمولاً از BufferQueues پیکربندی‌شده برای بافرینگ سه‌گانه استفاده می‌کنند. بافرها بنا به تقاضا اختصاص داده می‌شوند، بنابراین اگر تولیدکننده بافرها را به اندازه کافی آهسته تولید کند، مثلاً با سرعت 30 فریم در ثانیه روی یک نمایشگر 60 فریم در ثانیه، ممکن است فقط دو بافر اختصاص داده شده در صف وجود داشته باشد. تخصیص بافرها بنا به تقاضا به کاهش مصرف حافظه کمک می‌کند. می‌توانید خلاصه‌ای از بافرهای مرتبط با هر لایه را در خروجی dumpsys SurfaceFlinger مشاهده کنید.

بیشتر کلاینت‌ها با استفاده از OpenGL ES یا Vulkan روی سطوح رندر می‌گیرند. با این حال، برخی از کلاینت‌ها با استفاده از یک canvas روی سطوح رندر می‌کنند.

رندرینگ بوم

کتابخانه گرافیکی Skia پیاده‌سازی canvas را ارائه می‌دهد. اگر می‌خواهید یک مستطیل رسم کنید، API مربوط به Canvas را فراخوانی می‌کنید که بایت‌ها را در یک بافر به طور مناسب تنظیم می‌کند. برای اطمینان از اینکه یک بافر به طور همزمان توسط دو کلاینت به‌روزرسانی نمی‌شود یا هنگام نمایش در آن نوشته نمی‌شود، بافر را قفل کنید تا به آن دسترسی داشته باشید. برای کار با قفل‌های canvas از دستورات زیر استفاده کنید:

  • lockCanvas() بافر را برای رندر شدن روی CPU قفل می‌کند و یک Canvas برای استفاده جهت ترسیم برمی‌گرداند.
  • unlockCanvasAndPost() بافر را از حالت قفل خارج کرده و آن را به کامپوزیتور ارسال می‌کند.
  • lockHardwareCanvas() بافر را برای رندر کردن روی GPU قفل می‌کند و یک بوم نقاشی برای استفاده جهت ترسیم برمی‌گرداند.

اولین باری که تولیدکننده از BufferQueue درخواست بافر می‌کند، بافر تخصیص داده شده و با صفر مقداردهی اولیه می‌شود. مقداردهی اولیه برای جلوگیری از اشتراک‌گذاری سهوی داده‌ها بین فرآیندها ضروری است. با این حال، اگر از یک بافر دوباره استفاده کنید، محتویات قبلی هنوز وجود دارند. اگر بارها و بارها توابع lockCanvas() و unlockCanvasAndPost() را بدون ترسیم چیزی فراخوانی کنید، تولیدکننده بین فریم‌های رندر شده قبلی جابجا می‌شود.

کد قفل/باز کردن قفل سطح، ارجاعی به بافر رندر شده قبلی را نگه می‌دارد. اگر هنگام قفل کردن سطح، یک ناحیه کثیف مشخص کنید، پیکسل‌های غیر کثیف را از بافر قبلی کپی می‌کند. SurfaceFlinger یا HWC معمولاً بافر را مدیریت می‌کنند؛ اما از آنجا که فقط باید از بافر بخوانید، نیازی به انتظار برای دسترسی انحصاری نیست.

نگهدارنده سطح

SurfaceHolder رابطی است که سیستم برای اشتراک‌گذاری مالکیت سطوح با برنامه‌ها از آن استفاده می‌کند. برخی از کلاینت‌هایی که با سطوح کار می‌کنند، SurfaceHolder را می‌خواهند، زیرا APIها برای دریافت و تنظیم پارامترهای سطح از طریق SurfaceHolder پیاده‌سازی شده‌اند. SurfaceView شامل SurfaceHolder است.

بیشتر کامپوننت‌هایی که با یک نما (view) تعامل دارند، شامل یک SurfaceHolder هستند. برخی دیگر از APIها، مانند MediaCodec، روی خودِ سطح (surface) عمل می‌کنند.