summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2024-02-19 09:47:19 -0500
committerGravatar Liam2024-02-19 23:59:35 -0500
commit9f159dd62cbb1a4efe9c5cd724a94caf8c885793 (patch)
tree3b419db99ff18b0e7ea58789fd4767d888f3da58 /src
parentImport keys from filesystem. (#13056) (diff)
downloadyuzu-9f159dd62cbb1a4efe9c5cd724a94caf8c885793.tar.gz
yuzu-9f159dd62cbb1a4efe9c5cd724a94caf8c885793.tar.xz
yuzu-9f159dd62cbb1a4efe9c5cd724a94caf8c885793.zip
nvnflinger/vi: don't recreate buffer queue on open/close
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvnflinger/display.h26
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp12
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.cpp39
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.h6
-rw-r--r--src/core/hle/service/vi/container.cpp52
-rw-r--r--src/core/hle/service/vi/container.h3
-rw-r--r--src/core/hle/service/vi/layer.h16
-rw-r--r--src/core/hle/service/vi/layer_list.h6
8 files changed, 88 insertions, 72 deletions
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h
index f27cbf144..40aa59787 100644
--- a/src/core/hle/service/nvnflinger/display.h
+++ b/src/core/hle/service/nvnflinger/display.h
@@ -3,8 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list>
7
8#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 6#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
9#include "core/hle/service/nvnflinger/hwc_layer.h" 7#include "core/hle/service/nvnflinger/hwc_layer.h"
10 8
@@ -26,18 +24,12 @@ struct Layer {
26}; 24};
27 25
28struct LayerStack { 26struct LayerStack {
29 std::list<Layer> layers; 27 std::vector<std::shared_ptr<Layer>> layers;
30};
31
32struct Display {
33 explicit Display(u64 id_) {
34 id = id_;
35 }
36 28
37 Layer* FindLayer(s32 consumer_id) { 29 std::shared_ptr<Layer> FindLayer(s32 consumer_id) {
38 for (auto& layer : stack.layers) { 30 for (auto& layer : layers) {
39 if (layer.consumer_id == consumer_id) { 31 if (layer->consumer_id == consumer_id) {
40 return &layer; 32 return layer;
41 } 33 }
42 } 34 }
43 35
@@ -45,7 +37,13 @@ struct Display {
45 } 37 }
46 38
47 bool HasLayers() { 39 bool HasLayers() {
48 return !stack.layers.empty(); 40 return !layers.empty();
41 }
42};
43
44struct Display {
45 explicit Display(u64 id_) {
46 id = id_;
49 } 47 }
50 48
51 u64 id; 49 u64 id;
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index 02215a786..f2dfe85a9 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -55,10 +55,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
55 55
56 // Acquire all necessary framebuffers. 56 // Acquire all necessary framebuffers.
57 for (auto& layer : display.stack.layers) { 57 for (auto& layer : display.stack.layers) {
58 auto consumer_id = layer.consumer_id; 58 auto consumer_id = layer->consumer_id;
59 59
60 // Try to fetch the framebuffer (either new or stale). 60 // Try to fetch the framebuffer (either new or stale).
61 const auto result = this->CacheFramebufferLocked(layer, consumer_id); 61 const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
62 62
63 // If we failed, skip this layer. 63 // If we failed, skip this layer.
64 if (result == CacheStatus::NoBufferAvailable) { 64 if (result == CacheStatus::NoBufferAvailable) {
@@ -75,7 +75,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
75 const auto& igbp_buffer = *item.graphic_buffer; 75 const auto& igbp_buffer = *item.graphic_buffer;
76 76
77 // TODO: get proper Z-index from layer 77 // TODO: get proper Z-index from layer
78 if (layer.visible) { 78 if (layer->visible) {
79 composition_stack.emplace_back(HwcLayer{ 79 composition_stack.emplace_back(HwcLayer{
80 .buffer_handle = igbp_buffer.BufferId(), 80 .buffer_handle = igbp_buffer.BufferId(),
81 .offset = igbp_buffer.Offset(), 81 .offset = igbp_buffer.Offset(),
@@ -84,7 +84,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
84 .height = igbp_buffer.Height(), 84 .height = igbp_buffer.Height(),
85 .stride = igbp_buffer.Stride(), 85 .stride = igbp_buffer.Stride(),
86 .z_index = 0, 86 .z_index = 0,
87 .blending = layer.blending, 87 .blending = layer->blending,
88 .transform = static_cast<android::BufferTransformFlags>(item.transform), 88 .transform = static_cast<android::BufferTransformFlags>(item.transform),
89 .crop_rect = item.crop, 89 .crop_rect = item.crop,
90 .acquire_fence = item.fence, 90 .acquire_fence = item.fence,
@@ -134,7 +134,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
134 continue; 134 continue;
135 } 135 }
136 136
137 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { 137 if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
138 // TODO: support release fence 138 // TODO: support release fence
139 // This is needed to prevent screen tearing 139 // This is needed to prevent screen tearing
140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); 140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
@@ -153,7 +153,7 @@ void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_i
153 } 153 }
154 154
155 // Try to release the buffer item. 155 // Try to release the buffer item.
156 auto* const layer = display.FindLayer(consumer_id); 156 const auto layer = display.stack.FindLayer(consumer_id);
157 if (layer && it->second.is_acquired) { 157 if (layer && it->second.is_acquired) {
158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); 158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
159 } 159 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp
index 41a705717..8362b65e5 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.cpp
+++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp
@@ -36,7 +36,7 @@ void SurfaceFlinger::RemoveDisplay(u64 display_id) {
36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
37 u64 display_id) { 37 u64 display_id) {
38 auto* const display = this->FindDisplay(display_id); 38 auto* const display = this->FindDisplay(display_id);
39 if (!display || !display->HasLayers()) { 39 if (!display || !display->stack.HasLayers()) {
40 return false; 40 return false;
41 } 41 }
42 42
@@ -46,19 +46,34 @@ bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_spe
46 return true; 46 return true;
47} 47}
48 48
49void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { 49void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) {
50 auto* const display = this->FindDisplay(display_id);
51 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( 50 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
52 m_server.TryGetBinder(consumer_binder_id)); 51 m_server.TryGetBinder(consumer_binder_id));
53 52 if (!binder) {
54 if (!display || !binder) {
55 return; 53 return;
56 } 54 }
57 55
58 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); 56 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
59 buffer_item_consumer->Connect(false); 57 buffer_item_consumer->Connect(false);
60 58
61 display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); 59 m_layers.layers.emplace_back(
60 std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id));
61}
62
63void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) {
64 std::erase_if(m_layers.layers,
65 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
66}
67
68void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
69 auto* const display = this->FindDisplay(display_id);
70 auto layer = this->FindLayer(consumer_binder_id);
71
72 if (!display || !layer) {
73 return;
74 }
75
76 display->stack.layers.emplace_back(std::move(layer));
62} 77}
63 78
64void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { 79void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
@@ -69,18 +84,18 @@ void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_bi
69 84
70 m_composer.RemoveLayerLocked(*display, consumer_binder_id); 85 m_composer.RemoveLayerLocked(*display, consumer_binder_id);
71 std::erase_if(display->stack.layers, 86 std::erase_if(display->stack.layers,
72 [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); 87 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
73} 88}
74 89
75void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { 90void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
76 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 91 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
77 layer->visible = visible; 92 layer->visible = visible;
78 return; 93 return;
79 } 94 }
80} 95}
81 96
82void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { 97void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
83 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 98 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
84 layer->blending = blending; 99 layer->blending = blending;
85 return; 100 return;
86 } 101 }
@@ -96,9 +111,9 @@ Display* SurfaceFlinger::FindDisplay(u64 display_id) {
96 return nullptr; 111 return nullptr;
97} 112}
98 113
99Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { 114std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
100 for (auto& display : m_displays) { 115 for (auto& layer : m_layers.layers) {
101 if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { 116 if (layer->consumer_id == consumer_binder_id) {
102 return layer; 117 return layer;
103 } 118 }
104 } 119 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h
index d8c53fbda..406281c83 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.h
+++ b/src/core/hle/service/nvnflinger/surface_flinger.h
@@ -36,6 +36,9 @@ public:
36 void RemoveDisplay(u64 display_id); 36 void RemoveDisplay(u64 display_id);
37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
38 38
39 void CreateLayer(s32 consumer_binder_id);
40 void DestroyLayer(s32 consumer_binder_id);
41
39 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); 42 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
40 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); 43 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
41 44
@@ -44,7 +47,7 @@ public:
44 47
45private: 48private:
46 Display* FindDisplay(u64 display_id); 49 Display* FindDisplay(u64 display_id);
47 Layer* FindLayer(s32 consumer_binder_id); 50 std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
48 51
49public: 52public:
50 // TODO: these don't belong here 53 // TODO: these don't belong here
@@ -57,6 +60,7 @@ private:
57 KernelHelpers::ServiceContext m_context; 60 KernelHelpers::ServiceContext m_context;
58 61
59 std::vector<Display> m_displays; 62 std::vector<Display> m_displays;
63 LayerStack m_layers;
60 std::shared_ptr<Nvidia::Module> nvdrv; 64 std::shared_ptr<Nvidia::Module> nvdrv;
61 s32 disp_fd; 65 s32 disp_fd;
62 HardwareComposer m_composer; 66 HardwareComposer m_composer;
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp
index 310a207f1..9074f4ae0 100644
--- a/src/core/hle/service/vi/container.cpp
+++ b/src/core/hle/service/vi/container.cpp
@@ -43,11 +43,7 @@ void Container::OnTerminate() {
43 43
44 m_is_shut_down = true; 44 m_is_shut_down = true;
45 45
46 m_layers.ForEachLayer([&](auto& layer) { 46 m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); });
47 if (layer.IsOpen()) {
48 this->DestroyBufferQueueLocked(&layer);
49 }
50 });
51 47
52 m_displays.ForEachDisplay( 48 m_displays.ForEachDisplay(
53 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); 49 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
@@ -161,16 +157,29 @@ Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner
161 auto* const display = m_displays.GetDisplayById(display_id); 157 auto* const display = m_displays.GetDisplayById(display_id);
162 R_UNLESS(display != nullptr, VI::ResultNotFound); 158 R_UNLESS(display != nullptr, VI::ResultNotFound);
163 159
164 auto* const layer = m_layers.CreateLayer(owner_aruid, display); 160 s32 consumer_binder_id, producer_binder_id;
161 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
162
163 auto* const layer =
164 m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
165 R_UNLESS(layer != nullptr, VI::ResultNotFound); 165 R_UNLESS(layer != nullptr, VI::ResultNotFound);
166 166
167 m_surface_flinger->CreateLayer(consumer_binder_id);
168
167 *out_layer_id = layer->GetId(); 169 *out_layer_id = layer->GetId();
168 R_SUCCEED(); 170 R_SUCCEED();
169} 171}
170 172
171Result Container::DestroyLayerLocked(u64 layer_id) { 173Result Container::DestroyLayerLocked(u64 layer_id) {
172 R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); 174 auto* const layer = m_layers.GetLayerById(layer_id);
173 R_THROW(VI::ResultNotFound); 175 R_UNLESS(layer != nullptr, VI::ResultNotFound);
176
177 m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
178 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
179 layer->GetProducerBinderId());
180 m_layers.DestroyLayer(layer_id);
181
182 R_SUCCEED();
174} 183}
175 184
176Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { 185Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
@@ -181,7 +190,12 @@ Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64
181 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); 190 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
182 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); 191 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
183 192
184 this->CreateBufferQueueLocked(layer); 193 layer->Open();
194
195 if (auto* display = layer->GetDisplay(); display != nullptr) {
196 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
197 }
198
185 *out_producer_binder_id = layer->GetProducerBinderId(); 199 *out_producer_binder_id = layer->GetProducerBinderId();
186 200
187 R_SUCCEED(); 201 R_SUCCEED();
@@ -192,30 +206,14 @@ Result Container::CloseLayerLocked(u64 layer_id) {
192 R_UNLESS(layer != nullptr, VI::ResultNotFound); 206 R_UNLESS(layer != nullptr, VI::ResultNotFound);
193 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); 207 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
194 208
195 this->DestroyBufferQueueLocked(layer);
196
197 R_SUCCEED();
198}
199
200void Container::CreateBufferQueueLocked(Layer* layer) {
201 s32 consumer_binder_id, producer_binder_id;
202 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
203 layer->Open(consumer_binder_id, producer_binder_id);
204
205 if (auto* display = layer->GetDisplay(); display != nullptr) {
206 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
207 }
208}
209
210void Container::DestroyBufferQueueLocked(Layer* layer) {
211 if (auto* display = layer->GetDisplay(); display != nullptr) { 209 if (auto* display = layer->GetDisplay(); display != nullptr) {
212 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), 210 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
213 layer->GetConsumerBinderId()); 211 layer->GetConsumerBinderId());
214 } 212 }
215 213
216 layer->Close(); 214 layer->Close();
217 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), 215
218 layer->GetProducerBinderId()); 216 R_SUCCEED();
219} 217}
220 218
221bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 219bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h
index cd0d2ca86..5eac4d77d 100644
--- a/src/core/hle/service/vi/container.h
+++ b/src/core/hle/service/vi/container.h
@@ -72,9 +72,6 @@ private:
72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); 72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
73 Result CloseLayerLocked(u64 layer_id); 73 Result CloseLayerLocked(u64 layer_id);
74 74
75 void CreateBufferQueueLocked(Layer* layer);
76 void DestroyBufferQueueLocked(Layer* layer);
77
78public: 75public:
79 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 76 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
80 77
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h
index b85c8df61..e4c9c9864 100644
--- a/src/core/hle/service/vi/layer.h
+++ b/src/core/hle/service/vi/layer.h
@@ -13,29 +13,31 @@ class Layer {
13public: 13public:
14 constexpr Layer() = default; 14 constexpr Layer() = default;
15 15
16 void Initialize(u64 id, u64 owner_aruid, Display* display) { 16 void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id,
17 s32 producer_binder_id) {
17 m_id = id; 18 m_id = id;
18 m_owner_aruid = owner_aruid; 19 m_owner_aruid = owner_aruid;
19 m_display = display; 20 m_display = display;
21 m_consumer_binder_id = consumer_binder_id;
22 m_producer_binder_id = producer_binder_id;
20 m_is_initialized = true; 23 m_is_initialized = true;
21 } 24 }
22 25
23 void Finalize() { 26 void Finalize() {
24 m_id = {}; 27 m_id = {};
28 m_owner_aruid = {};
25 m_display = {}; 29 m_display = {};
30 m_consumer_binder_id = {};
31 m_producer_binder_id = {};
26 m_is_initialized = {}; 32 m_is_initialized = {};
27 } 33 }
28 34
29 void Open(s32 consumer_binder_id, s32 producer_binder_id) { 35 void Open() {
30 m_consumer_binder_id = consumer_binder_id;
31 m_producer_binder_id = producer_binder_id;
32 m_is_open = true; 36 m_is_open = true;
33 } 37 }
34 38
35 void Close() { 39 void Close() {
36 m_producer_binder_id = {}; 40 m_is_open = false;
37 m_consumer_binder_id = {};
38 m_is_open = {};
39 } 41 }
40 42
41 u64 GetId() const { 43 u64 GetId() const {
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h
index 1738ede9a..4afca6f40 100644
--- a/src/core/hle/service/vi/layer_list.h
+++ b/src/core/hle/service/vi/layer_list.h
@@ -11,13 +11,15 @@ class LayerList {
11public: 11public:
12 constexpr LayerList() = default; 12 constexpr LayerList() = default;
13 13
14 Layer* CreateLayer(u64 owner_aruid, Display* display) { 14 Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id,
15 s32 producer_binder_id) {
15 Layer* const layer = GetFreeLayer(); 16 Layer* const layer = GetFreeLayer();
16 if (!layer) { 17 if (!layer) {
17 return nullptr; 18 return nullptr;
18 } 19 }
19 20
20 layer->Initialize(++m_next_id, owner_aruid, display); 21 layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id,
22 producer_binder_id);
21 return layer; 23 return layer;
22 } 24 }
23 25