[framebuffer] Use display layer API

Test: Run gfxtest and vkcube
Change-Id: I5f97af64f8f3c5efaf7acf8c23388f230b782a1b
diff --git a/system/ulib/framebuffer/framebuffer.c b/system/ulib/framebuffer/framebuffer.c
index de1bcde..21a76f0 100644
--- a/system/ulib/framebuffer/framebuffer.c
+++ b/system/ulib/framebuffer/framebuffer.c
@@ -25,17 +25,33 @@
 
 static int32_t txid;
 static int32_t display_id;
+static int32_t layer_id;
 
 static int32_t width;
 static int32_t height;
 static int32_t stride;
 static zx_pixel_format_t format;
+static bool type_set;
+static uint32_t image_type;
 
 static zx_handle_t vmo = ZX_HANDLE_INVALID;
 
 static bool inited = false;
 static bool in_single_buffer_mode;
 
+static zx_status_t set_layer_config(int32_t layer_id, uint32_t width, uint32_t height,
+                                    zx_pixel_format_t format, int32_t type) {
+    fuchsia_display_ControllerSetLayerPrimaryConfigRequest layer_cfg_msg;
+    layer_cfg_msg.hdr.ordinal = fuchsia_display_ControllerSetLayerPrimaryConfigOrdinal;
+    layer_cfg_msg.layer_id = layer_id;
+    layer_cfg_msg.image_config.width = width;
+    layer_cfg_msg.image_config.height = height;
+    layer_cfg_msg.image_config.pixel_format = format;
+    layer_cfg_msg.image_config.type = type;
+
+    return zx_channel_write(dc_handle, 0, &layer_cfg_msg, sizeof(layer_cfg_msg), NULL, 0);
+}
+
 zx_status_t fb_bind(bool single_buffer, const char** err_msg_out) {
     const char* err_msg;
     if (!err_msg_out) {
@@ -116,13 +132,62 @@
         goto err;
     }
 
+    fuchsia_display_ControllerCreateLayerRequest create_layer_msg;
+    create_layer_msg.hdr.ordinal = fuchsia_display_ControllerCreateLayerOrdinal;
+
+    fuchsia_display_ControllerCreateLayerResponse create_layer_rsp;
+    zx_channel_call_args_t call_args = {};
+    call_args.wr_bytes = &create_layer_msg;
+    call_args.rd_bytes = &create_layer_rsp;
+    call_args.wr_num_bytes = sizeof(create_layer_msg);
+    call_args.rd_num_bytes = sizeof(create_layer_rsp);
+    if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args,
+                                  &actual_bytes, &actual_handles, &read_status)) != ZX_OK) {
+        *err_msg_out = "Create layer call failed";
+        status = (status == ZX_ERR_CALL_FAILED ? read_status : status);
+        goto err;
+    }
+    if (create_layer_rsp.res != ZX_OK) {
+        *err_msg_out = "Failed to create layer";
+        status = create_layer_rsp.res;
+        goto err;
+    }
+
+    uint8_t fidl_bytes[sizeof(fuchsia_display_ControllerSetDisplayLayersRequest)
+                       + FIDL_ALIGN(sizeof(uint64_t))];
+    fuchsia_display_ControllerSetDisplayLayersRequest* set_display_layer_request =
+            (fuchsia_display_ControllerSetDisplayLayersRequest*) fidl_bytes;
+    *(uint64_t*)(fidl_bytes + sizeof(fuchsia_display_ControllerSetDisplayLayersRequest)) =
+            create_layer_rsp.layer_id;
+
+    set_display_layer_request->hdr.ordinal = fuchsia_display_ControllerSetDisplayLayersOrdinal;
+    set_display_layer_request->display_id = display->id;
+    set_display_layer_request->layer_ids.count = 1;
+    set_display_layer_request->layer_ids.data = (void*) FIDL_ALLOC_PRESENT;
+
+    if ((status = zx_channel_write(dc_handle, 0, fidl_bytes,
+                                   sizeof(fidl_bytes), NULL, 0)) != ZX_OK) {
+        *err_msg_out = "Failed to set display layers";
+        goto err;
+    }
+
+    if ((status = set_layer_config(create_layer_rsp.layer_id, mode->horizontal_resolution,
+                                   mode->vertical_resolution, pixel_format,
+                                   IMAGE_TYPE_SIMPLE)) != ZX_OK) {
+        *err_msg_out = "Failed to set layer config";
+        goto err;
+    }
+
     display_id = display->id;
+    layer_id = create_layer_rsp.layer_id;
 
     width = mode->horizontal_resolution;
     height = mode->vertical_resolution;
     format = pixel_format;
     stride = stride_rsp.stride;
 
+    type_set = false;
+
     inited = true;
 
     if (single_buffer) {
@@ -236,6 +301,16 @@
     ZX_ASSERT(inited && !in_single_buffer_mode);
     zx_status_t status;
 
+    if (type_set && type != image_type) {
+        return ZX_ERR_BAD_STATE;
+    } else if (!type_set && type != IMAGE_TYPE_SIMPLE) {
+        if ((status = set_layer_config(layer_id, width, height, format, type)) != ZX_OK) {
+            return status;
+        }
+        image_type = type;
+        type_set = true;
+    }
+
     fuchsia_display_ControllerImportVmoImageRequest import_msg;
     import_msg.hdr.ordinal = fuchsia_display_ControllerImportVmoImageOrdinal;
     import_msg.hdr.txid = txid++;
@@ -322,10 +397,10 @@
     ZX_ASSERT(inited && !in_single_buffer_mode);
     zx_status_t status;
 
-    fuchsia_display_ControllerSetDisplayImageRequest set_msg;
-    set_msg.hdr.ordinal = fuchsia_display_ControllerSetDisplayImageOrdinal;
+    fuchsia_display_ControllerSetLayerImageRequest set_msg;
+    set_msg.hdr.ordinal = fuchsia_display_ControllerSetLayerImageOrdinal;
     set_msg.hdr.txid = txid++;
-    set_msg.display = display_id;
+    set_msg.layer_id = layer_id;
     set_msg.image_id = image_id;
     set_msg.wait_event_id = wait_event_id;
     set_msg.present_event_id = present_event_id;
diff --git a/system/ulib/framebuffer/include/lib/framebuffer/framebuffer.h b/system/ulib/framebuffer/include/lib/framebuffer/framebuffer.h
index d10d201..6de608d 100644
--- a/system/ulib/framebuffer/include/lib/framebuffer/framebuffer.h
+++ b/system/ulib/framebuffer/include/lib/framebuffer/framebuffer.h
@@ -40,7 +40,7 @@
 //
 // If |type| is 0, the imported image has a linear memory layout. For any other
 // values, it is the responsibility of the image producer and display driver to
-// coordinate the meaning of |type|.
+// coordinate the meaning of |type|. All imported images must have the same type.
 zx_status_t fb_import_image(zx_handle_t handle, uint32_t type, uint64_t *id_out);
 void fb_release_image(uint64_t id);