X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=hwcomposer.cpp;h=e0483e90fdf5b86f49839bbbc473bffdee86a7bc;hb=80b1a5d903a7f9e14d9cde2de7f996185271a739;hp=5181d840047e2111529225a7fbc8388f86a713a6;hpb=7acc59be7f12ad45b9abfa56c2d21726edf6224e;p=android-x86%2Fexternal-drm_hwcomposer.git diff --git a/hwcomposer.cpp b/hwcomposer.cpp index 5181d84..e0483e9 100644 --- a/hwcomposer.cpp +++ b/hwcomposer.cpp @@ -17,13 +17,16 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #define LOG_TAG "hwcomposer-drm" -#include "drm_hwcomposer.h" +#include "drmhwcomposer.h" +#include "drmeventlistener.h" #include "drmresources.h" -#include "importer.h" +#include "platform.h" +#include "virtualcompositorworker.h" #include "vsyncworker.h" #include +#include #include #include #include @@ -45,7 +48,6 @@ #include #define UM_PER_INCH 25400 -#define HWC_FB_BUFFERS 3 namespace android { @@ -124,201 +126,93 @@ typedef struct hwc_drm_display { VSyncWorker vsync_worker; } hwc_drm_display_t; -struct hwc_context_t { - // map of display:hwc_drm_display_t - typedef std::map DisplayMap; - typedef DisplayMap::iterator DisplayMapIter; - - hwc_context_t() : procs(NULL), importer(NULL), use_framebuffer_target(false) { - } - - ~hwc_context_t() { - delete importer; +class DrmHotplugHandler : public DrmEventHandler { + public: + void Init(DrmResources *drm, const struct hwc_procs *procs) { + drm_ = drm; + procs_ = procs; } - hwc_composer_device_1_t device; - hwc_procs_t const *procs; + void HandleEvent(uint64_t timestamp_us) { + for (auto &conn : drm_->connectors()) { + drmModeConnection old_state = conn->state(); - DisplayMap displays; - DrmResources drm; - Importer *importer; - const gralloc_module_t *gralloc; - DummySwSyncTimeline dummy_timeline; - bool use_framebuffer_target; -}; + conn->UpdateModes(); -static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { - native_handle_t *new_handle = - native_handle_create(handle->numFds, handle->numInts); - if (new_handle == NULL) - return NULL; + drmModeConnection cur_state = conn->state(); - const int *old_data = handle->data; - int *new_data = new_handle->data; - for (int i = 0; i < handle->numFds; i++) { - *new_data = dup(*old_data); - old_data++; - new_data++; - } - memcpy(new_data, old_data, sizeof(int) * handle->numInts); + if (cur_state == old_state) + continue; - return new_handle; -} + ALOGI("%s event @%" PRIu64 " for connector %u\n", + cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, + conn->id()); -static void free_buffer_handle(native_handle_t *handle) { - int ret = native_handle_close(handle); - if (ret) - ALOGE("Failed to close native handle %d", ret); - ret = native_handle_delete(handle); - if (ret) - ALOGE("Failed to delete native handle %d", ret); -} + if (cur_state == DRM_MODE_CONNECTED) { + // Take the first one, then look for the preferred + DrmMode mode = *(conn->modes().begin()); + for (auto &m : conn->modes()) { + if (m.type() & DRM_MODE_TYPE_PREFERRED) { + mode = m; + break; + } + } + ALOGI("Setting mode %dx%d for connector %d\n", mode.h_display(), + mode.v_display(), conn->id()); + int ret = drm_->SetDisplayActiveMode(conn->display(), mode); + if (ret) { + ALOGE("Failed to set active config %d", ret); + return; + } + } else { + int ret = drm_->SetDpmsMode(conn->display(), DRM_MODE_DPMS_OFF); + if (ret) { + ALOGE("Failed to set dpms mode off %d", ret); + return; + } + } -OutputFd &OutputFd::operator=(OutputFd &&rhs) { - if (fd_ == NULL) { - std::swap(fd_, rhs.fd_); - } else { - if (*fd_ < 0) { - ALOGE("Failed to fill OutputFd %p before assignment", fd_); + procs_->hotplug(procs_, conn->display(), + cur_state == DRM_MODE_CONNECTED ? 1 : 0); } - fd_ = rhs.fd_; - rhs.fd_ = NULL; - } - - return *this; -} - -hwc_drm_bo *DrmHwcBuffer::operator->() { - if (importer_ == NULL) { - ALOGE("Access of none existent BO"); - exit(1); - return NULL; - } - return &bo_; -} - -void DrmHwcBuffer::Clear() { - if (importer_ != NULL) { - importer_->ReleaseBuffer(&bo_); - importer_ = NULL; - } -} - -int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer) { - hwc_drm_bo tmp_bo; - - int ret = importer->ImportBuffer(handle, &tmp_bo); - if (ret) - return ret; - - if (importer_ != NULL) { - importer_->ReleaseBuffer(&bo_); - } - - importer_ = importer; - - bo_ = tmp_bo; - - return 0; -} - -int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle, - const gralloc_module_t *gralloc) { - native_handle_t *handle_copy = dup_buffer_handle(handle); - if (handle_copy == NULL) { - ALOGE("Failed to duplicate handle"); - return -ENOMEM; - } - - int ret = gralloc->registerBuffer(gralloc, handle_copy); - if (ret) { - ALOGE("Failed to register buffer handle %d", ret); - free_buffer_handle(handle_copy); - return ret; } - Clear(); - - gralloc_ = gralloc; - handle_ = handle_copy; - - return 0; -} + private: + DrmResources *drm_ = NULL; + const struct hwc_procs *procs_ = NULL; +}; -DrmHwcNativeHandle::~DrmHwcNativeHandle() { - Clear(); -} +struct hwc_context_t { + // map of display:hwc_drm_display_t + typedef std::map DisplayMap; -void DrmHwcNativeHandle::Clear() { - if (gralloc_ != NULL && handle_ != NULL) { - gralloc_->unregisterBuffer(gralloc_, handle_); - free_buffer_handle(handle_); - gralloc_ = NULL; - handle_ = NULL; + ~hwc_context_t() { + virtual_compositor_worker.Exit(); } -} -int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, - const gralloc_module_t *gralloc) { - sf_handle = sf_layer->handle; - int ret = buffer.ImportBuffer(sf_layer->handle, importer); - if (ret) - return ret; - - ret = handle.CopyBufferHandle(sf_layer->handle, gralloc); - if (ret) - return ret; + hwc_composer_device_1_t device; + hwc_procs_t const *procs = NULL; - alpha = sf_layer->planeAlpha; + DisplayMap displays; + DrmResources drm; + std::unique_ptr importer; + const gralloc_module_t *gralloc; + DummySwSyncTimeline dummy_timeline; + VirtualCompositorWorker virtual_compositor_worker; + DrmHotplugHandler hotplug_handler; +}; - switch (sf_layer->transform) { - case 0: - transform = DrmHwcTransform::kIdentity; - break; - case HWC_TRANSFORM_FLIP_H: - transform = DrmHwcTransform::kFlipH; - break; - case HWC_TRANSFORM_FLIP_V: - transform = DrmHwcTransform::kFlipV; - break; - case HWC_TRANSFORM_ROT_90: - transform = DrmHwcTransform::kRotate90; - break; - case HWC_TRANSFORM_ROT_180: - transform = DrmHwcTransform::kRotate180; - break; - case HWC_TRANSFORM_ROT_270: - transform = DrmHwcTransform::kRotate270; - break; - default: - ALOGE("Invalid transform in hwc_layer_1_t %d", sf_layer->transform); - return -EINVAL; +class DrmVsyncCallback : public VsyncCallback { + public: + DrmVsyncCallback(hwc_procs_t const *procs) : procs_(procs) { } - switch (sf_layer->blending) { - case HWC_BLENDING_NONE: - blending = DrmHwcBlending::kNone; - break; - case HWC_BLENDING_PREMULT: - blending = DrmHwcBlending::kPreMult; - break; - case HWC_BLENDING_COVERAGE: - blending = DrmHwcBlending::kCoverage; - break; - default: - ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending); - return -EINVAL; + void Callback(int display, int64_t timestamp) { + procs_->vsync(procs_, display, timestamp); } - - source_crop = DrmHwcRect( - sf_layer->sourceCropf.left, sf_layer->sourceCropf.top, - sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom); - display_frame = DrmHwcRect( - sf_layer->displayFrame.left, sf_layer->displayFrame.top, - sf_layer->displayFrame.right, sf_layer->displayFrame.bottom); - - return 0; -} + private: + hwc_procs_t const *procs_; +}; static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff, int buff_len) { @@ -327,36 +221,66 @@ static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff, ctx->drm.compositor()->Dump(&out); std::string out_str = out.str(); - strncpy(buff, out_str.c_str(), std::min((size_t)buff_len, out_str.length())); + strncpy(buff, out_str.c_str(), + std::min((size_t)buff_len, out_str.length() + 1)); + buff[buff_len - 1] = '\0'; +} + +static bool hwc_skip_layer(const std::pair &indices, int i) { + return indices.first >= 0 && i >= indices.first && i <= indices.second; } static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays, hwc_display_contents_1_t **display_contents) { struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - char use_framebuffer_target[PROPERTY_VALUE_MAX]; - property_get("hwc.drm.use_framebuffer_target", use_framebuffer_target, "0"); - bool new_use_framebuffer_target = atoi(use_framebuffer_target); - if (ctx->use_framebuffer_target != new_use_framebuffer_target) - ALOGW("Starting to %s HWC_FRAMEBUFFER_TARGET", - new_use_framebuffer_target ? "use" : "not use"); - ctx->use_framebuffer_target = new_use_framebuffer_target; - for (int i = 0; i < (int)num_displays; ++i) { if (!display_contents[i]) continue; - DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i); - if (!crtc) { - ALOGE("No crtc for display %d", i); - return -ENODEV; + bool use_framebuffer_target = false; + DrmMode mode; + if (i == HWC_DISPLAY_VIRTUAL) { + use_framebuffer_target = true; + } else { + DrmConnector *c = ctx->drm.GetConnectorForDisplay(i); + if (!c) { + ALOGE("Failed to get DrmConnector for display %d", i); + return -ENODEV; + } + mode = c->active_mode(); } + // Since we can't composite HWC_SKIP_LAYERs by ourselves, we'll let SF + // handle all layers in between the first and last skip layers. So find the + // outer indices and mark everything in between as HWC_FRAMEBUFFER + std::pair skip_layer_indices(-1, -1); int num_layers = display_contents[i]->numHwLayers; - for (int j = 0; j < num_layers; j++) { + for (int j = 0; !use_framebuffer_target && j < num_layers; ++j) { + hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j]; + + if (!(layer->flags & HWC_SKIP_LAYER)) + continue; + + if (skip_layer_indices.first == -1) + skip_layer_indices.first = j; + skip_layer_indices.second = j; + } + + for (int j = 0; j < num_layers; ++j) { hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j]; - if (!ctx->use_framebuffer_target) { + if (!use_framebuffer_target && !hwc_skip_layer(skip_layer_indices, j)) { + // If the layer is off the screen, don't earmark it for an overlay. + // We'll leave it as-is, which effectively just drops it from the frame + const hwc_rect_t *frame = &layer->displayFrame; + if ((frame->right - frame->left) <= 0 || + (frame->bottom - frame->top) <= 0 || + frame->right <= 0 || frame->bottom <= 0 || + frame->left >= (int)mode.h_display() || + frame->top >= (int)mode.v_display()) + continue; + if (layer->compositionType == HWC_FRAMEBUFFER) layer->compositionType = HWC_OVERLAY; } else { @@ -415,6 +339,11 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, if (!sf_display_contents[i]) continue; + if (i == HWC_DISPLAY_VIRTUAL) { + ctx->virtual_compositor_worker.QueueComposite(dc); + continue; + } + std::ostringstream display_index_formatter; display_index_formatter << "retire fence for display " << i; std::string display_fence_description(display_index_formatter.str()); @@ -427,23 +356,38 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, int framebuffer_target_index = -1; for (size_t j = 0; j < num_dc_layers; ++j) { hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; + if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) { + framebuffer_target_index = j; + break; + } + } + + for (size_t j = 0; j < num_dc_layers; ++j) { + hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; display_contents.layers.emplace_back(); DrmHwcLayer &layer = display_contents.layers.back(); - if (sf_layer->flags & HWC_SKIP_LAYER) + // In prepare() we marked all layers FRAMEBUFFER between SKIP_LAYER's. + // This means we should insert the FB_TARGET layer in the composition + // stack at the location of the first skip layer, and ignore the rest. + if (sf_layer->flags & HWC_SKIP_LAYER) { + if (framebuffer_target_index < 0) + continue; + int idx = framebuffer_target_index; + framebuffer_target_index = -1; + hwc_layer_1_t *fbt_layer = &dc->hwLayers[idx]; + if (!fbt_layer->handle || (fbt_layer->flags & HWC_SKIP_LAYER)) { + ALOGE("Invalid HWC_FRAMEBUFFER_TARGET with HWC_SKIP_LAYER present"); + continue; + } + indices_to_composite.push_back(idx); continue; - - if (!ctx->use_framebuffer_target) { - if (sf_layer->compositionType == HWC_OVERLAY) - indices_to_composite.push_back(j); - if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) - framebuffer_target_index = j; - } else { - if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) - indices_to_composite.push_back(j); } + if (sf_layer->compositionType == HWC_OVERLAY) + indices_to_composite.push_back(j); + layer.acquire_fence.Set(sf_layer->acquireFenceFd); sf_layer->acquireFenceFd = -1; @@ -457,23 +401,18 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, layer.release_fence = OutputFd(&sf_layer->releaseFenceFd); } - if (ctx->use_framebuffer_target) { - if (indices_to_composite.size() != 1) { - ALOGE("Expected 1 (got %d) layer with HWC_FRAMEBUFFER_TARGET", - indices_to_composite.size()); + // This is a catch-all in case we get a frame without any overlay layers, or + // skip layers, but with a value fb_target layer. This _shouldn't_ happen, + // but it's not ruled out by the hwc specification + if (indices_to_composite.empty() && framebuffer_target_index >= 0) { + hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index]; + if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) { + ALOGE( + "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all " + "HWC_OVERLAY layers are skipped."); ret = -EINVAL; } - } else { - if (indices_to_composite.empty() && framebuffer_target_index >= 0) { - hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index]; - if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) { - ALOGE( - "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all " - "HWC_OVERLAY layers are skipped."); - ret = -EINVAL; - } - indices_to_composite.push_back(framebuffer_target_index); - } + indices_to_composite.push_back(framebuffer_target_index); } } @@ -483,24 +422,31 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, for (size_t i = 0; i < num_displays; ++i) { hwc_display_contents_1_t *dc = sf_display_contents[i]; DrmHwcDisplayContents &display_contents = displays_contents[i]; - if (!sf_display_contents[i]) + if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL) continue; layers_map.emplace_back(); DrmCompositionDisplayLayersMap &map = layers_map.back(); + map.display = i; + map.geometry_changed = + (dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED; std::vector &indices_to_composite = layers_indices[i]; for (size_t j : indices_to_composite) { hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; DrmHwcLayer &layer = display_contents.layers[j]; - layer.InitFromHwcLayer(sf_layer, ctx->importer, ctx->gralloc); + ret = layer.InitFromHwcLayer(sf_layer, ctx->importer.get(), ctx->gralloc); + if (ret) { + ALOGE("Failed to init composition from layer %d", ret); + return ret; + } map.layers.emplace_back(std::move(layer)); } } std::unique_ptr composition( - ctx->drm.compositor()->CreateComposition(ctx->importer)); + ctx->drm.compositor()->CreateComposition(ctx->importer.get())); if (!composition) { ALOGE("Drm composition init failed"); return -EINVAL; @@ -516,6 +462,20 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, return -EINVAL; } + for (size_t i = 0; i < num_displays; ++i) { + hwc_display_contents_1_t *dc = sf_display_contents[i]; + if (!dc) + continue; + + size_t num_dc_layers = dc->numHwLayers; + for (size_t j = 0; j < num_dc_layers; ++j) { + hwc_layer_1_t *layer = &dc->hwLayers[j]; + if (layer->flags & HWC_SKIP_LAYER) + continue; + hwc_add_layer_to_retire_fence(layer, dc); + } + } + composition.reset(NULL); return ret; @@ -562,7 +522,8 @@ static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what, *value = 1000 * 1000 * 1000 / 60; break; case HWC_DISPLAY_TYPES_SUPPORTED: - *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL; + *value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT | + HWC_DISPLAY_VIRTUAL_BIT; break; } return 0; @@ -574,10 +535,13 @@ static void hwc_register_procs(struct hwc_composer_device_1 *dev, ctx->procs = procs; - for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin(); - iter != ctx->displays.end(); ++iter) { - iter->second.vsync_worker.SetProcs(procs); + for (std::pair &display_entry : ctx->displays) { + auto callback = std::make_shared(procs); + display_entry.second.vsync_worker.RegisterCallback(std::move(callback)); } + + ctx->hotplug_handler.Init(&ctx->drm, procs); + ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler); } static int hwc_get_display_configs(struct hwc_composer_device_1 *dev, @@ -602,13 +566,12 @@ static int hwc_get_display_configs(struct hwc_composer_device_1 *dev, return ret; } - for (DrmConnector::ModeIter iter = connector->begin_modes(); - iter != connector->end_modes(); ++iter) { + for (const DrmMode &mode : connector->modes()) { size_t idx = hd->config_ids.size(); if (idx == *num_configs) break; - hd->config_ids.push_back(iter->id()); - configs[idx] = iter->id(); + hd->config_ids.push_back(mode.id()); + configs[idx] = mode.id(); } *num_configs = hd->config_ids.size(); return *num_configs == 0 ? -1 : 0; @@ -625,10 +588,9 @@ static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev, return -ENODEV; } DrmMode mode; - for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes(); - ++iter) { - if (iter->id() == config) { - mode = *iter; + for (const DrmMode &conn_mode : c->modes()) { + if (conn_mode.id() == config) { + mode = conn_mode; break; } } @@ -696,11 +658,14 @@ static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display, ALOGE("Failed to get connector for display %d", display); return -ENODEV; } + + if (c->state() != DRM_MODE_CONNECTED) + return -ENODEV; + DrmMode mode; - for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes(); - ++iter) { - if (iter->id() == hd->config_ids[index]) { - mode = *iter; + for (const DrmMode &conn_mode : c->modes()) { + if (conn_mode.id() == hd->config_ids[index]) { + mode = conn_mode; break; } } @@ -713,6 +678,11 @@ static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display, ALOGE("Failed to set active config %d", ret); return ret; } + ret = ctx->drm.SetDpmsMode(display, DRM_MODE_DPMS_ON); + if (ret) { + ALOGE("Failed to set dpms mode on %d", ret); + return ret; + } return ret; } @@ -766,15 +736,19 @@ static int hwc_initialize_display(struct hwc_context_t *ctx, int display) { static int hwc_enumerate_displays(struct hwc_context_t *ctx) { int ret; - for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors(); - c != ctx->drm.end_connectors(); ++c) { - ret = hwc_initialize_display(ctx, (*c)->display()); + for (auto &conn : ctx->drm.connectors()) { + ret = hwc_initialize_display(ctx, conn->display()); if (ret) { - ALOGE("Failed to initialize display %d", (*c)->display()); + ALOGE("Failed to initialize display %d", conn->display()); return ret; } } + ret = ctx->virtual_compositor_worker.Init(); + if (ret) { + ALOGE("Failed to initialize virtual compositor worker"); + return ret; + } return 0; } @@ -785,7 +759,7 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name, return -EINVAL; } - struct hwc_context_t *ctx = new hwc_context_t(); + std::unique_ptr ctx(new hwc_context_t()); if (!ctx) { ALOGE("Failed to allocate hwc context"); return -ENOMEM; @@ -794,7 +768,6 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name, int ret = ctx->drm.Init(); if (ret) { ALOGE("Can't initialize Drm object %d", ret); - delete ctx; return ret; } @@ -802,7 +775,6 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name, (const hw_module_t **)&ctx->gralloc); if (ret) { ALOGE("Failed to open gralloc module %d", ret); - delete ctx; return ret; } @@ -812,17 +784,15 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name, return ret; } - ctx->importer = Importer::CreateInstance(&ctx->drm); + ctx->importer.reset(Importer::CreateInstance(&ctx->drm)); if (!ctx->importer) { ALOGE("Failed to create importer instance"); - delete ctx; return ret; } - ret = hwc_enumerate_displays(ctx); + ret = hwc_enumerate_displays(ctx.get()); if (ret) { ALOGE("Failed to enumerate displays: %s", strerror(ret)); - delete ctx; return ret; } @@ -845,25 +815,26 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name, ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */ *dev = &ctx->device.common; + ctx.release(); return 0; } } static struct hw_module_methods_t hwc_module_methods = { - open : android::hwc_device_open + .open = android::hwc_device_open }; hwc_module_t HAL_MODULE_INFO_SYM = { - common : { - tag : HARDWARE_MODULE_TAG, - version_major : 1, - version_minor : 0, - id : HWC_HARDWARE_MODULE_ID, - name : "DRM hwcomposer module", - author : "The Android Open Source Project", - methods : &hwc_module_methods, - dso : NULL, - reserved : {0}, + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = HWC_HARDWARE_MODULE_ID, + .name = "DRM hwcomposer module", + .author = "The Android Open Source Project", + .methods = &hwc_module_methods, + .dso = NULL, + .reserved = {0}, } };