1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
6 
7 #include <xf86drm.h>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/check.h"
12 #include "base/stl_util.h"
13 #include "skia/ext/legacy_display_globals.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
17 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
18 
19 // Private types defined in libdrm. Define them here so we can peek at the
20 // commit and ensure the expected state has been set correctly.
21 struct drmModeAtomicReqItem {
22   uint32_t object_id;
23   uint32_t property_id;
24   uint64_t value;
25 };
26 
27 typedef drmModeAtomicReqItem* drmModeAtomicReqItemPtr;
28 
29 struct _drmModeAtomicReq {
30   uint32_t cursor;
31   uint32_t size_items;
32   drmModeAtomicReqItemPtr items;
33 };
34 
35 namespace ui {
36 
37 namespace {
38 
39 constexpr uint32_t kTestModesetFlags =
40     DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET;
41 
42 constexpr uint32_t kCommitModesetFlags = DRM_MODE_ATOMIC_ALLOW_MODESET;
43 
44 template <class Object>
DrmAllocator()45 Object* DrmAllocator() {
46   return static_cast<Object*>(drmMalloc(sizeof(Object)));
47 }
48 
CreatePropertyObject(const std::vector<DrmDevice::Property> & properties)49 ScopedDrmObjectPropertyPtr CreatePropertyObject(
50     const std::vector<DrmDevice::Property>& properties) {
51   ScopedDrmObjectPropertyPtr drm_properties(
52       DrmAllocator<drmModeObjectProperties>());
53   drm_properties->count_props = properties.size();
54   drm_properties->props = static_cast<uint32_t*>(
55       drmMalloc(sizeof(uint32_t) * drm_properties->count_props));
56   drm_properties->prop_values = static_cast<uint64_t*>(
57       drmMalloc(sizeof(uint64_t) * drm_properties->count_props));
58   for (size_t i = 0; i < properties.size(); ++i) {
59     drm_properties->props[i] = properties[i].id;
60     drm_properties->prop_values[i] = properties[i].value;
61   }
62 
63   return drm_properties;
64 }
65 
66 template <class Type>
FindObjectById(uint32_t id,std::vector<Type> & properties)67 Type* FindObjectById(uint32_t id, std::vector<Type>& properties) {
68   auto it = std::find_if(properties.begin(), properties.end(),
69                          [id](const Type& p) { return p.id == id; });
70   return it != properties.end() ? &(*it) : nullptr;
71 }
72 
73 }  // namespace
74 
75 MockDrmDevice::CrtcProperties::CrtcProperties() = default;
76 MockDrmDevice::CrtcProperties::CrtcProperties(const CrtcProperties&) = default;
77 MockDrmDevice::CrtcProperties::~CrtcProperties() = default;
78 
79 MockDrmDevice::ConnectorProperties::ConnectorProperties() = default;
80 MockDrmDevice::ConnectorProperties::ConnectorProperties(
81     const ConnectorProperties&) = default;
82 MockDrmDevice::ConnectorProperties::~ConnectorProperties() = default;
83 
84 MockDrmDevice::PlaneProperties::PlaneProperties() = default;
85 MockDrmDevice::PlaneProperties::PlaneProperties(const PlaneProperties&) =
86     default;
87 MockDrmDevice::PlaneProperties::~PlaneProperties() = default;
88 
MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device)89 MockDrmDevice::MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device)
90     : DrmDevice(base::FilePath(),
91                 base::File(),
92                 true /* is_primary_device */,
93                 std::move(gbm_device)),
94       get_crtc_call_count_(0),
95       set_crtc_call_count_(0),
96       add_framebuffer_call_count_(0),
97       remove_framebuffer_call_count_(0),
98       page_flip_call_count_(0),
99       overlay_clear_call_count_(0),
100       allocate_buffer_count_(0),
101       set_crtc_expectation_(true),
102       add_framebuffer_expectation_(true),
103       page_flip_expectation_(true),
104       create_dumb_buffer_expectation_(true),
105       current_framebuffer_(0) {
106   plane_manager_ = std::make_unique<HardwareDisplayPlaneManagerLegacy>(this);
107 }
108 
109 MockDrmDevice::~MockDrmDevice() = default;
110 
111 // static
AllocateInFormatsBlob(uint32_t id,const std::vector<uint32_t> & supported_formats,const std::vector<drm_format_modifier> & supported_format_modifiers)112 ScopedDrmPropertyBlobPtr MockDrmDevice::AllocateInFormatsBlob(
113     uint32_t id,
114     const std::vector<uint32_t>& supported_formats,
115     const std::vector<drm_format_modifier>& supported_format_modifiers) {
116   drm_format_modifier_blob header;
117   header.count_formats = supported_formats.size();
118   header.formats_offset = sizeof(header);
119   header.count_modifiers = supported_format_modifiers.size();
120   header.modifiers_offset =
121       header.formats_offset + sizeof(uint32_t) * header.count_formats;
122 
123   ScopedDrmPropertyBlobPtr blob(DrmAllocator<drmModePropertyBlobRes>());
124   blob->id = id;
125   blob->length = header.modifiers_offset +
126                  sizeof(drm_format_modifier) * header.count_modifiers;
127   blob->data = drmMalloc(blob->length);
128 
129   memcpy(blob->data, &header, sizeof(header));
130   memcpy(static_cast<uint8_t*>(blob->data) + header.formats_offset,
131          supported_formats.data(), sizeof(uint32_t) * header.count_formats);
132   memcpy(static_cast<uint8_t*>(blob->data) + header.modifiers_offset,
133          supported_format_modifiers.data(),
134          sizeof(drm_format_modifier) * header.count_modifiers);
135 
136   return blob;
137 }
138 
InitializeState(const std::vector<CrtcProperties> & crtc_properties,const std::vector<ConnectorProperties> & connector_properties,const std::vector<PlaneProperties> & plane_properties,const std::map<uint32_t,std::string> & property_names,bool use_atomic)139 void MockDrmDevice::InitializeState(
140     const std::vector<CrtcProperties>& crtc_properties,
141     const std::vector<ConnectorProperties>& connector_properties,
142     const std::vector<PlaneProperties>& plane_properties,
143     const std::map<uint32_t, std::string>& property_names,
144     bool use_atomic) {
145   CHECK(InitializeStateWithResult(crtc_properties, connector_properties,
146                                   plane_properties, property_names,
147                                   use_atomic));
148 }
149 
InitializeStateWithResult(const std::vector<CrtcProperties> & crtc_properties,const std::vector<ConnectorProperties> & connector_properties,const std::vector<PlaneProperties> & plane_properties,const std::map<uint32_t,std::string> & property_names,bool use_atomic)150 bool MockDrmDevice::InitializeStateWithResult(
151     const std::vector<CrtcProperties>& crtc_properties,
152     const std::vector<ConnectorProperties>& connector_properties,
153     const std::vector<PlaneProperties>& plane_properties,
154     const std::map<uint32_t, std::string>& property_names,
155     bool use_atomic) {
156   UpdateState(crtc_properties, connector_properties, plane_properties,
157               property_names);
158   if (use_atomic) {
159     plane_manager_ = std::make_unique<HardwareDisplayPlaneManagerAtomic>(this);
160   } else {
161     plane_manager_ = std::make_unique<HardwareDisplayPlaneManagerLegacy>(this);
162   }
163 
164   return plane_manager_->Initialize();
165 }
166 
UpdateState(const std::vector<CrtcProperties> & crtc_properties,const std::vector<ConnectorProperties> & connector_properties,const std::vector<PlaneProperties> & plane_properties,const std::map<uint32_t,std::string> & property_names)167 void MockDrmDevice::UpdateState(
168     const std::vector<CrtcProperties>& crtc_properties,
169     const std::vector<ConnectorProperties>& connector_properties,
170     const std::vector<PlaneProperties>& plane_properties,
171     const std::map<uint32_t, std::string>& property_names) {
172   crtc_properties_ = crtc_properties;
173   connector_properties_ = connector_properties;
174   plane_properties_ = plane_properties;
175   property_names_ = property_names;
176 }
177 
GetResources()178 ScopedDrmResourcesPtr MockDrmDevice::GetResources() {
179   ScopedDrmResourcesPtr resources(DrmAllocator<drmModeRes>());
180   resources->count_crtcs = crtc_properties_.size();
181   resources->crtcs = static_cast<uint32_t*>(
182       drmMalloc(sizeof(uint32_t) * resources->count_crtcs));
183   for (size_t i = 0; i < crtc_properties_.size(); ++i)
184     resources->crtcs[i] = crtc_properties_[i].id;
185 
186   resources->count_connectors = connector_properties_.size();
187   resources->connectors = static_cast<uint32_t*>(
188       drmMalloc(sizeof(uint32_t) * resources->count_connectors));
189   for (size_t i = 0; i < connector_properties_.size(); ++i)
190     resources->connectors[i] = connector_properties_[i].id;
191 
192   return resources;
193 }
194 
GetPlaneResources()195 ScopedDrmPlaneResPtr MockDrmDevice::GetPlaneResources() {
196   ScopedDrmPlaneResPtr resources(DrmAllocator<drmModePlaneRes>());
197   resources->count_planes = plane_properties_.size();
198   resources->planes = static_cast<uint32_t*>(
199       drmMalloc(sizeof(uint32_t) * resources->count_planes));
200   for (size_t i = 0; i < plane_properties_.size(); ++i)
201     resources->planes[i] = plane_properties_[i].id;
202 
203   return resources;
204 }
205 
GetObjectProperties(uint32_t object_id,uint32_t object_type)206 ScopedDrmObjectPropertyPtr MockDrmDevice::GetObjectProperties(
207     uint32_t object_id,
208     uint32_t object_type) {
209   if (object_type == DRM_MODE_OBJECT_PLANE) {
210     PlaneProperties* properties = FindObjectById(object_id, plane_properties_);
211     if (properties)
212       return CreatePropertyObject(properties->properties);
213   } else if (object_type == DRM_MODE_OBJECT_CRTC) {
214     CrtcProperties* properties = FindObjectById(object_id, crtc_properties_);
215     if (properties)
216       return CreatePropertyObject(properties->properties);
217   } else if (object_type == DRM_MODE_OBJECT_CONNECTOR) {
218     ConnectorProperties* properties =
219         FindObjectById(object_id, connector_properties_);
220     if (properties)
221       return CreatePropertyObject(properties->properties);
222   }
223 
224   return nullptr;
225 }
226 
GetCrtc(uint32_t crtc_id)227 ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) {
228   get_crtc_call_count_++;
229   return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>());
230 }
231 
SetCrtc(uint32_t crtc_id,uint32_t framebuffer,std::vector<uint32_t> connectors,const drmModeModeInfo & mode)232 bool MockDrmDevice::SetCrtc(uint32_t crtc_id,
233                             uint32_t framebuffer,
234                             std::vector<uint32_t> connectors,
235                             const drmModeModeInfo& mode) {
236   crtc_fb_[crtc_id] = framebuffer;
237   current_framebuffer_ = framebuffer;
238   set_crtc_call_count_++;
239   return set_crtc_expectation_;
240 }
241 
DisableCrtc(uint32_t crtc_id)242 bool MockDrmDevice::DisableCrtc(uint32_t crtc_id) {
243   current_framebuffer_ = 0;
244   return true;
245 }
246 
GetConnector(uint32_t connector_id)247 ScopedDrmConnectorPtr MockDrmDevice::GetConnector(uint32_t connector_id) {
248   return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>());
249 }
250 
AddFramebuffer2(uint32_t width,uint32_t height,uint32_t format,uint32_t handles[4],uint32_t strides[4],uint32_t offsets[4],uint64_t modifiers[4],uint32_t * framebuffer,uint32_t flags)251 bool MockDrmDevice::AddFramebuffer2(uint32_t width,
252                                     uint32_t height,
253                                     uint32_t format,
254                                     uint32_t handles[4],
255                                     uint32_t strides[4],
256                                     uint32_t offsets[4],
257                                     uint64_t modifiers[4],
258                                     uint32_t* framebuffer,
259                                     uint32_t flags) {
260   add_framebuffer_call_count_++;
261   *framebuffer = add_framebuffer_call_count_;
262   framebuffer_ids_.insert(*framebuffer);
263   return add_framebuffer_expectation_;
264 }
265 
RemoveFramebuffer(uint32_t framebuffer)266 bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
267   {
268     auto it = framebuffer_ids_.find(framebuffer);
269     CHECK(it != framebuffer_ids_.end());
270     framebuffer_ids_.erase(it);
271   }
272   remove_framebuffer_call_count_++;
273   std::vector<uint32_t> crtcs_to_clear;
274   for (auto crtc_fb : crtc_fb_) {
275     if (crtc_fb.second == framebuffer)
276       crtcs_to_clear.push_back(crtc_fb.first);
277   }
278   for (auto crtc : crtcs_to_clear)
279     crtc_fb_[crtc] = 0;
280   return true;
281 }
282 
GetFramebuffer(uint32_t framebuffer)283 ScopedDrmFramebufferPtr MockDrmDevice::GetFramebuffer(uint32_t framebuffer) {
284   return ScopedDrmFramebufferPtr();
285 }
286 
PageFlip(uint32_t crtc_id,uint32_t framebuffer,scoped_refptr<PageFlipRequest> page_flip_request)287 bool MockDrmDevice::PageFlip(uint32_t crtc_id,
288                              uint32_t framebuffer,
289                              scoped_refptr<PageFlipRequest> page_flip_request) {
290   page_flip_call_count_++;
291   DCHECK(page_flip_request);
292   crtc_fb_[crtc_id] = framebuffer;
293   current_framebuffer_ = framebuffer;
294   if (page_flip_expectation_)
295     callbacks_.push(page_flip_request->AddPageFlip());
296   return page_flip_expectation_;
297 }
298 
GetPlane(uint32_t plane_id)299 ScopedDrmPlanePtr MockDrmDevice::GetPlane(uint32_t plane_id) {
300   PlaneProperties* properties = FindObjectById(plane_id, plane_properties_);
301   if (!properties)
302     return nullptr;
303 
304   ScopedDrmPlanePtr plane(DrmAllocator<drmModePlane>());
305   plane->possible_crtcs = properties->crtc_mask;
306   return plane;
307 }
308 
GetProperty(drmModeConnector * connector,const char * name)309 ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector,
310                                                 const char* name) {
311   return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
312 }
313 
GetProperty(uint32_t id)314 ScopedDrmPropertyPtr MockDrmDevice::GetProperty(uint32_t id) {
315   auto it = property_names_.find(id);
316   if (it == property_names_.end())
317     return nullptr;
318 
319   ScopedDrmPropertyPtr property(DrmAllocator<drmModePropertyRes>());
320   property->prop_id = id;
321   strcpy(property->name, it->second.c_str());
322   return property;
323 }
324 
SetProperty(uint32_t connector_id,uint32_t property_id,uint64_t value)325 bool MockDrmDevice::SetProperty(uint32_t connector_id,
326                                 uint32_t property_id,
327                                 uint64_t value) {
328   return true;
329 }
330 
CreatePropertyBlob(const void * blob,size_t size)331 ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(const void* blob,
332                                                         size_t size) {
333   uint32_t id = ++property_id_generator_;
334   allocated_property_blobs_.insert(id);
335   return std::make_unique<DrmPropertyBlobMetadata>(this, id);
336 }
337 
DestroyPropertyBlob(uint32_t id)338 void MockDrmDevice::DestroyPropertyBlob(uint32_t id) {
339   EXPECT_TRUE(allocated_property_blobs_.erase(id));
340 }
341 
GetCapability(uint64_t capability,uint64_t * value)342 bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
343   return true;
344 }
345 
GetPropertyBlob(uint32_t property_id)346 ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(uint32_t property_id) {
347   auto it = blob_property_map_.find(property_id);
348   if (it == blob_property_map_.end())
349     return nullptr;
350 
351   ScopedDrmPropertyBlobPtr blob(DrmAllocator<drmModePropertyBlobRes>());
352   blob->id = property_id;
353   blob->length = it->second->length;
354   blob->data = drmMalloc(blob->length);
355   memcpy(blob->data, it->second->data, blob->length);
356 
357   return blob;
358 }
359 
GetPropertyBlob(drmModeConnector * connector,const char * name)360 ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(
361     drmModeConnector* connector,
362     const char* name) {
363   return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>());
364 }
365 
SetObjectProperty(uint32_t object_id,uint32_t object_type,uint32_t property_id,uint32_t property_value)366 bool MockDrmDevice::SetObjectProperty(uint32_t object_id,
367                                       uint32_t object_type,
368                                       uint32_t property_id,
369                                       uint32_t property_value) {
370   set_object_property_count_++;
371   return true;
372 }
373 
SetCursor(uint32_t crtc_id,uint32_t handle,const gfx::Size & size)374 bool MockDrmDevice::SetCursor(uint32_t crtc_id,
375                               uint32_t handle,
376                               const gfx::Size& size) {
377   crtc_cursor_map_[crtc_id] = handle;
378   return true;
379 }
380 
MoveCursor(uint32_t crtc_id,const gfx::Point & point)381 bool MockDrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
382   return true;
383 }
384 
CreateDumbBuffer(const SkImageInfo & info,uint32_t * handle,uint32_t * stride)385 bool MockDrmDevice::CreateDumbBuffer(const SkImageInfo& info,
386                                      uint32_t* handle,
387                                      uint32_t* stride) {
388   if (!create_dumb_buffer_expectation_)
389     return false;
390 
391   *handle = allocate_buffer_count_++;
392   *stride = info.minRowBytes();
393   void* pixels = new char[info.computeByteSize(*stride)];
394   SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
395   buffers_.push_back(SkSurface::MakeRasterDirectReleaseProc(
396       info, pixels, *stride,
397       [](void* pixels, void* context) { delete[] static_cast<char*>(pixels); },
398       /*context=*/nullptr, &props));
399   buffers_[*handle]->getCanvas()->clear(SK_ColorBLACK);
400 
401   return true;
402 }
403 
DestroyDumbBuffer(uint32_t handle)404 bool MockDrmDevice::DestroyDumbBuffer(uint32_t handle) {
405   if (handle >= buffers_.size() || !buffers_[handle])
406     return false;
407 
408   buffers_[handle].reset();
409   return true;
410 }
411 
MapDumbBuffer(uint32_t handle,size_t size,void ** pixels)412 bool MockDrmDevice::MapDumbBuffer(uint32_t handle, size_t size, void** pixels) {
413   if (handle >= buffers_.size() || !buffers_[handle])
414     return false;
415 
416   SkPixmap pixmap;
417   buffers_[handle]->peekPixels(&pixmap);
418   *pixels = const_cast<void*>(pixmap.addr());
419   return true;
420 }
421 
UnmapDumbBuffer(void * pixels,size_t size)422 bool MockDrmDevice::UnmapDumbBuffer(void* pixels, size_t size) {
423   return true;
424 }
425 
CloseBufferHandle(uint32_t handle)426 bool MockDrmDevice::CloseBufferHandle(uint32_t handle) {
427   return true;
428 }
429 
CommitProperties(drmModeAtomicReq * request,uint32_t flags,uint32_t crtc_count,scoped_refptr<PageFlipRequest> page_flip_request)430 bool MockDrmDevice::CommitProperties(
431     drmModeAtomicReq* request,
432     uint32_t flags,
433     uint32_t crtc_count,
434     scoped_refptr<PageFlipRequest> page_flip_request) {
435   if (flags == kTestModesetFlags)
436     ++test_modeset_count_;
437   else if (flags == kCommitModesetFlags)
438     ++commit_modeset_count_;
439 
440   commit_count_++;
441   if (!commit_expectation_)
442     return false;
443 
444   for (uint32_t i = 0; i < request->cursor; ++i) {
445     bool res = ValidatePropertyValue(request->items[i].property_id,
446                                      request->items[i].value);
447     if (!res)
448       return false;
449   }
450 
451   if (page_flip_request)
452     callbacks_.push(page_flip_request->AddPageFlip());
453 
454   if (flags & DRM_MODE_ATOMIC_TEST_ONLY)
455     return true;
456 
457   // Only update values if not testing.
458   for (uint32_t i = 0; i < request->cursor; ++i) {
459     bool res =
460         UpdateProperty(request->items[i].object_id,
461                        request->items[i].property_id, request->items[i].value);
462     if (!res)
463       return false;
464   }
465 
466   return true;
467 }
468 
SetGammaRamp(uint32_t crtc_id,const std::vector<display::GammaRampRGBEntry> & lut)469 bool MockDrmDevice::SetGammaRamp(
470     uint32_t crtc_id,
471     const std::vector<display::GammaRampRGBEntry>& lut) {
472   set_gamma_ramp_count_++;
473   return legacy_gamma_ramp_expectation_;
474 }
475 
SetCapability(uint64_t capability,uint64_t value)476 bool MockDrmDevice::SetCapability(uint64_t capability, uint64_t value) {
477   return true;
478 }
479 
GetFramebufferForCrtc(uint32_t crtc_id) const480 uint32_t MockDrmDevice::GetFramebufferForCrtc(uint32_t crtc_id) const {
481   auto it = crtc_fb_.find(crtc_id);
482   return it != crtc_fb_.end() ? it->second : 0u;
483 }
484 
RunCallbacks()485 void MockDrmDevice::RunCallbacks() {
486   while (!callbacks_.empty()) {
487     PageFlipCallback callback = std::move(callbacks_.front());
488     callbacks_.pop();
489     std::move(callback).Run(0, base::TimeTicks());
490   }
491 }
492 
SetPropertyBlob(ScopedDrmPropertyBlobPtr blob)493 void MockDrmDevice::SetPropertyBlob(ScopedDrmPropertyBlobPtr blob) {
494   blob_property_map_[blob->id] = std::move(blob);
495 }
496 
UpdateProperty(uint32_t id,uint64_t value,std::vector<DrmDevice::Property> * properties)497 bool MockDrmDevice::UpdateProperty(
498     uint32_t id,
499     uint64_t value,
500     std::vector<DrmDevice::Property>* properties) {
501   DrmDevice::Property* property = FindObjectById(id, *properties);
502   if (!property)
503     return false;
504 
505   property->value = value;
506   return true;
507 }
508 
UpdateProperty(uint32_t object_id,uint32_t property_id,uint64_t value)509 bool MockDrmDevice::UpdateProperty(uint32_t object_id,
510                                    uint32_t property_id,
511                                    uint64_t value) {
512   PlaneProperties* plane_properties =
513       FindObjectById(object_id, plane_properties_);
514   if (plane_properties)
515     return UpdateProperty(property_id, value, &plane_properties->properties);
516 
517   CrtcProperties* crtc_properties = FindObjectById(object_id, crtc_properties_);
518   if (crtc_properties)
519     return UpdateProperty(property_id, value, &crtc_properties->properties);
520 
521   ConnectorProperties* connector_properties =
522       FindObjectById(object_id, connector_properties_);
523   if (connector_properties) {
524     return UpdateProperty(property_id, value,
525                           &connector_properties->properties);
526   }
527 
528   return false;
529 }
530 
ValidatePropertyValue(uint32_t id,uint64_t value)531 bool MockDrmDevice::ValidatePropertyValue(uint32_t id, uint64_t value) {
532   auto it = property_names_.find(id);
533   if (it == property_names_.end())
534     return false;
535 
536   if (value == 0)
537     return true;
538 
539   std::vector<std::string> blob_properties = {"CTM", "DEGAMMA_LUT", "GAMMA_LUT",
540                                               "PLANE_CTM"};
541   if (base::Contains(blob_properties, it->second))
542     return base::Contains(allocated_property_blobs_, value);
543 
544   return true;
545 }
546 
547 }  // namespace ui
548