Flutter Engine
 
Loading...
Searching...
No Matches
flutter::ImageDecoderImpeller Class Referencefinal

#include <image_decoder_impeller.h>

Inheritance diagram for flutter::ImageDecoderImpeller:
flutter::ImageDecoder

Public Member Functions

 ImageDecoderImpeller (const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, const fml::WeakPtr< IOManager > &io_manager, bool supports_wide_gamut, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
 
 ~ImageDecoderImpeller () override
 
void Decode (fml::RefPtr< ImageDescriptor > descriptor, uint32_t target_width, uint32_t target_height, const ImageResult &result) override
 
- Public Member Functions inherited from flutter::ImageDecoder
virtual ~ImageDecoder ()
 
fml::TaskRunnerAffineWeakPtr< ImageDecoderGetWeakPtr () const
 

Static Public Member Functions

static DecompressResult DecompressTexture (ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< const impeller::Capabilities > &capabilities, const std::shared_ptr< impeller::Allocator > &allocator)
 
static void UploadTextureToPrivate (ImageResult result, const std::shared_ptr< impeller::Context > &context, const std::shared_ptr< impeller::DeviceBuffer > &buffer, const SkImageInfo &image_info, const std::shared_ptr< SkBitmap > &bitmap, const std::optional< SkImageInfo > &resize_info, const std::shared_ptr< const fml::SyncSwitch > &gpu_disabled_switch)
 Create a device private texture from the provided host buffer.
 
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToStorage (const std::shared_ptr< impeller::Context > &context, std::shared_ptr< SkBitmap > bitmap)
 Create a texture from the provided bitmap.
 
- Static Public Member Functions inherited from flutter::ImageDecoder
static std::unique_ptr< ImageDecoderMake (const Settings &settings, const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, const fml::WeakPtr< IOManager > &io_manager, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
 

Additional Inherited Members

- Public Types inherited from flutter::ImageDecoder
using ImageResult = std::function< void(sk_sp< DlImage >, std::string)>
 
- Protected Member Functions inherited from flutter::ImageDecoder
 ImageDecoder (const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager)
 
- Protected Attributes inherited from flutter::ImageDecoder
TaskRunners runners_
 
std::shared_ptr< fml::ConcurrentTaskRunnerconcurrent_task_runner_
 
fml::WeakPtr< IOManagerio_manager_
 

Detailed Description

Definition at line 50 of file image_decoder_impeller.h.

Constructor & Destructor Documentation

◆ ImageDecoderImpeller()

flutter::ImageDecoderImpeller::ImageDecoderImpeller ( const TaskRunners runners,
std::shared_ptr< fml::ConcurrentTaskRunner concurrent_task_runner,
const fml::WeakPtr< IOManager > &  io_manager,
bool  supports_wide_gamut,
const std::shared_ptr< fml::SyncSwitch > &  gpu_disabled_switch 
)

Definition at line 95 of file image_decoder_impeller.cc.

101 : ImageDecoder(runners, std::move(concurrent_task_runner), io_manager),
102 wide_gamut_enabled_(wide_gamut_enabled),
103 gpu_disabled_switch_(gpu_disabled_switch) {
104 std::promise<std::shared_ptr<impeller::Context>> context_promise;
105 context_ = context_promise.get_future();
107 [promise = std::move(context_promise), io_manager]() mutable {
108 if (io_manager) {
109 promise.set_value(io_manager->GetImpellerContext());
110 } else {
111 promise.set_value(nullptr);
112 }
113 }));
114}
ImageDecoder(const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager)
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
virtual void PostTask(const fml::closure &task) override
internal::CopyableLambda< T > MakeCopyable(T lambda)

References flutter::TaskRunners::GetIOTaskRunner(), fml::MakeCopyable(), fml::TaskRunner::PostTask(), and flutter::ImageDecoder::runners_.

◆ ~ImageDecoderImpeller()

flutter::ImageDecoderImpeller::~ImageDecoderImpeller ( )
overridedefault

Member Function Documentation

◆ Decode()

void flutter::ImageDecoderImpeller::Decode ( fml::RefPtr< ImageDescriptor descriptor,
uint32_t  target_width,
uint32_t  target_height,
const ImageResult result 
)
overridevirtual

Implements flutter::ImageDecoder.

Definition at line 532 of file image_decoder_impeller.cc.

535 {
536 FML_DCHECK(descriptor);
537 FML_DCHECK(p_result);
538
539 // Wrap the result callback so that it can be invoked from any thread.
540 auto raw_descriptor = descriptor.get();
541 raw_descriptor->AddRef();
542 ImageResult result = [p_result, //
543 raw_descriptor, //
544 ui_runner = runners_.GetUITaskRunner() //
545 ](const auto& image, const auto& decode_error) {
546 ui_runner->PostTask([raw_descriptor, p_result, image, decode_error]() {
547 raw_descriptor->Release();
548 p_result(std::move(image), decode_error);
549 });
550 };
551
552 concurrent_task_runner_->PostTask(
553 [raw_descriptor, //
554 context = context_.get(), //
555 target_size = SkISize::Make(target_width, target_height), //
556 io_runner = runners_.GetIOTaskRunner(), //
557 result,
558 wide_gamut_enabled = wide_gamut_enabled_, //
559 gpu_disabled_switch = gpu_disabled_switch_]() {
560#if FML_OS_IOS_SIMULATOR
561 // No-op backend.
562 if (!context) {
563 return;
564 }
565#endif // FML_OS_IOS_SIMULATOR
566
567 if (!context) {
568 result(nullptr, "No Impeller context is available");
569 return;
570 }
571 auto max_size_supported =
572 context->GetResourceAllocator()->GetMaxTextureSizeSupported();
573
574 // Always decompress on the concurrent runner.
575 auto bitmap_result = DecompressTexture(
576 raw_descriptor, target_size, max_size_supported,
577 /*supports_wide_gamut=*/wide_gamut_enabled &&
578 context->GetCapabilities()->SupportsExtendedRangeFormats(),
579 context->GetCapabilities(), context->GetResourceAllocator());
580 if (!bitmap_result.device_buffer) {
581 result(nullptr, bitmap_result.decode_error);
582 return;
583 }
584
585 auto upload_texture_and_invoke_result = [result, context, bitmap_result,
586 gpu_disabled_switch]() {
587 UploadTextureToPrivate(result, context, //
588 bitmap_result.device_buffer, //
589 bitmap_result.image_info, //
590 bitmap_result.sk_bitmap, //
591 bitmap_result.resize_info, //
592 gpu_disabled_switch //
593 );
594 };
595 // The I/O image uploads are not threadsafe on GLES.
596 if (context->GetBackendType() ==
598 io_runner->PostTask(upload_texture_and_invoke_result);
599 } else {
600 upload_texture_and_invoke_result();
601 }
602 });
603}
std::function< void(sk_sp< DlImage >, std::string)> ImageResult
std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner_
static DecompressResult DecompressTexture(ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< const impeller::Capabilities > &capabilities, const std::shared_ptr< impeller::Allocator > &allocator)
static void UploadTextureToPrivate(ImageResult result, const std::shared_ptr< impeller::Context > &context, const std::shared_ptr< impeller::DeviceBuffer > &buffer, const SkImageInfo &image_info, const std::shared_ptr< SkBitmap > &bitmap, const std::optional< SkImageInfo > &resize_info, const std::shared_ptr< const fml::SyncSwitch > &gpu_disabled_switch)
Create a device private texture from the provided host buffer.
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
T * get() const
Definition ref_ptr.h:117
FlutterVulkanImage * image
#define FML_DCHECK(condition)
Definition logging.h:122

References FML_DCHECK, fml::RefPtr< T >::get(), image, and impeller::Context::kOpenGLES.

◆ DecompressTexture()

DecompressResult flutter::ImageDecoderImpeller::DecompressTexture ( ImageDescriptor descriptor,
SkISize  target_size,
impeller::ISize  max_texture_size,
bool  supports_wide_gamut,
const std::shared_ptr< const impeller::Capabilities > &  capabilities,
const std::shared_ptr< impeller::Allocator > &  allocator 
)
static
  1. Decode the image.
  1. If the decoded image isn't the requested target size and the src size exceeds the device max texture size, perform a slow CPU resize.

Definition at line 131 of file image_decoder_impeller.cc.

137 {
138 TRACE_EVENT0("impeller", __FUNCTION__);
139 if (!descriptor) {
140 std::string decode_error("Invalid descriptor (should never happen)");
141 FML_DLOG(ERROR) << decode_error;
142 return DecompressResult{.decode_error = decode_error};
143 }
144
145 target_size.set(std::min(static_cast<int32_t>(max_texture_size.width),
146 target_size.width()),
147 std::min(static_cast<int32_t>(max_texture_size.height),
148 target_size.height()));
149
150 const SkISize source_size = descriptor->image_info().dimensions();
151 auto decode_size = source_size;
152 if (descriptor->is_compressed()) {
153 decode_size = descriptor->get_scaled_dimensions(std::max(
154 static_cast<float>(target_size.width()) / source_size.width(),
155 static_cast<float>(target_size.height()) / source_size.height()));
156 }
157
158 //----------------------------------------------------------------------------
159 /// 1. Decode the image.
160 ///
161
162 const auto base_image_info = descriptor->image_info();
163 const bool is_wide_gamut =
164 supports_wide_gamut ? IsWideGamut(base_image_info.colorSpace()) : false;
165 SkAlphaType alpha_type =
166 ChooseCompatibleAlphaType(base_image_info.alphaType());
167 SkImageInfo image_info;
168 if (is_wide_gamut) {
169 SkColorType color_type = alpha_type == SkAlphaType::kOpaque_SkAlphaType
170 ? kBGR_101010x_XR_SkColorType
171 : kRGBA_F16_SkColorType;
172 image_info =
173 base_image_info.makeWH(decode_size.width(), decode_size.height())
174 .makeColorType(color_type)
175 .makeAlphaType(alpha_type)
176 .makeColorSpace(SkColorSpace::MakeSRGB());
177 } else {
178 image_info =
179 base_image_info.makeWH(decode_size.width(), decode_size.height())
180 .makeColorType(
181 ChooseCompatibleColorType(base_image_info.colorType()))
182 .makeAlphaType(alpha_type)
183 .makeColorSpace(SkColorSpace::MakeSRGB());
184 }
185
186 const auto pixel_format = ToPixelFormat(image_info.colorType());
187 if (!pixel_format.has_value()) {
188 std::string decode_error(
189 std::format("Codec pixel format is not supported (SkColorType={})",
190 static_cast<int>(image_info.colorType())));
191 FML_DLOG(ERROR) << decode_error;
192 return DecompressResult{.decode_error = decode_error};
193 }
194
195 auto bitmap = std::make_shared<SkBitmap>();
196 bitmap->setInfo(image_info);
197 auto bitmap_allocator = std::make_shared<ImpellerAllocator>(allocator);
198
199 if (descriptor->is_compressed()) {
200 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
201 std::string decode_error(
202 "Could not allocate intermediate for image decompression.");
203 FML_DLOG(ERROR) << decode_error;
204 return DecompressResult{.decode_error = decode_error};
205 }
206 // Decode the image into the image generator's closest supported size.
207 if (!descriptor->get_pixels(bitmap->pixmap())) {
208 std::string decode_error("Could not decompress image.");
209 FML_DLOG(ERROR) << decode_error;
210 return DecompressResult{.decode_error = decode_error};
211 }
212 } else {
213 auto temp_bitmap = std::make_shared<SkBitmap>();
214 temp_bitmap->setInfo(base_image_info);
215 auto pixel_ref = SkMallocPixelRef::MakeWithData(
216 base_image_info, descriptor->row_bytes(), descriptor->data());
217 temp_bitmap->setPixelRef(pixel_ref, 0, 0);
218
219 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
220 std::string decode_error(
221 "Could not allocate intermediate for pixel conversion.");
222 FML_DLOG(ERROR) << decode_error;
223 return DecompressResult{.decode_error = decode_error};
224 }
225 temp_bitmap->readPixels(bitmap->pixmap());
226 bitmap->setImmutable();
227 }
228
229 // If the image is unpremultiplied, fix it.
230 if (alpha_type == SkAlphaType::kUnpremul_SkAlphaType) {
231 // Single copy of ImpellerAllocator crashes.
232 auto premul_allocator = std::make_shared<ImpellerAllocator>(allocator);
233 auto premul_bitmap = std::make_shared<SkBitmap>();
234 premul_bitmap->setInfo(bitmap->info().makeAlphaType(kPremul_SkAlphaType));
235 if (!premul_bitmap->tryAllocPixels(premul_allocator.get())) {
236 std::string decode_error(
237 "Could not allocate intermediate for premultiplication conversion.");
238 FML_DLOG(ERROR) << decode_error;
239 return DecompressResult{.decode_error = decode_error};
240 }
241 // readPixels() handles converting pixels to premultiplied form.
242 bitmap->readPixels(premul_bitmap->pixmap());
243 premul_bitmap->setImmutable();
244 bitmap_allocator = premul_allocator;
245 bitmap = premul_bitmap;
246 }
247
248 std::shared_ptr<impeller::DeviceBuffer> buffer =
249 bitmap_allocator->GetDeviceBuffer();
250 if (!buffer) {
251 return DecompressResult{.decode_error = "Unable to get device buffer"};
252 }
253 buffer->Flush();
254
255 std::optional<SkImageInfo> resize_info =
256 bitmap->dimensions() == target_size
257 ? std::nullopt
258 : std::optional<SkImageInfo>(image_info.makeDimensions(target_size));
259
260 if (source_size.width() > max_texture_size.width ||
261 source_size.height() > max_texture_size.height ||
262 !capabilities->SupportsTextureToTextureBlits()) {
263 //----------------------------------------------------------------------------
264 /// 2. If the decoded image isn't the requested target size and the src size
265 /// exceeds the device max texture size, perform a slow CPU resize.
266 ///
267 TRACE_EVENT0("impeller", "SlowCPUDecodeScale");
268 const auto scaled_image_info = image_info.makeDimensions(target_size);
269
270 auto scaled_bitmap = std::make_shared<SkBitmap>();
271 auto scaled_allocator = std::make_shared<ImpellerAllocator>(allocator);
272 scaled_bitmap->setInfo(scaled_image_info);
273 if (!scaled_bitmap->tryAllocPixels(scaled_allocator.get())) {
274 std::string decode_error(
275 "Could not allocate scaled bitmap for image decompression.");
276 FML_DLOG(ERROR) << decode_error;
277 return DecompressResult{.decode_error = decode_error};
278 }
279 if (!bitmap->pixmap().scalePixels(
280 scaled_bitmap->pixmap(),
281 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone))) {
282 FML_LOG(ERROR) << "Could not scale decoded bitmap data.";
283 }
284 scaled_bitmap->setImmutable();
285
286 std::shared_ptr<impeller::DeviceBuffer> buffer =
287 scaled_allocator->GetDeviceBuffer();
288 if (!buffer) {
289 return DecompressResult{.decode_error = "Unable to get device buffer"};
290 }
291 buffer->Flush();
292
293 return DecompressResult{.device_buffer = std::move(buffer),
294 .sk_bitmap = scaled_bitmap,
295 .image_info = scaled_bitmap->info()};
296 }
297
298 return DecompressResult{.device_buffer = std::move(buffer),
299 .sk_bitmap = bitmap,
300 .image_info = bitmap->info(),
301 .resize_info = resize_info};
302}
#define FML_DLOG(severity)
Definition logging.h:121
#define FML_LOG(severity)
Definition logging.h:101
static SkAlphaType ChooseCompatibleAlphaType(SkAlphaType type)
static SkColorType ChooseCompatibleColorType(SkColorType type)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
constexpr PixelFormat ToPixelFormat(vk::Format format)
Definition formats_vk.h:183
uint32_t color_type
uint32_t alpha_type
Type height
Definition size.h:29
Type width
Definition size.h:28
#define TRACE_EVENT0(category_group, name)

References alpha_type, flutter::buffer, flutter::ChooseCompatibleAlphaType(), flutter::ChooseCompatibleColorType(), color_type, flutter::ImageDescriptor::data(), flutter::DecompressResult::decode_error, flutter::DecompressResult::device_buffer, FML_DLOG, FML_LOG, flutter::ImageDescriptor::get_pixels(), flutter::ImageDescriptor::get_scaled_dimensions(), impeller::TSize< T >::height, flutter::ImageDescriptor::image_info(), flutter::ImageDescriptor::is_compressed(), flutter::ImageDescriptor::row_bytes(), impeller::ToPixelFormat(), TRACE_EVENT0, and impeller::TSize< T >::width.

Referenced by flutter::testing::TEST(), flutter::testing::TEST(), flutter::testing::TEST(), flutter::testing::TEST(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ UploadTextureToPrivate()

void flutter::ImageDecoderImpeller::UploadTextureToPrivate ( ImageResult  result,
const std::shared_ptr< impeller::Context > &  context,
const std::shared_ptr< impeller::DeviceBuffer > &  buffer,
const SkImageInfo &  image_info,
const std::shared_ptr< SkBitmap > &  bitmap,
const std::optional< SkImageInfo > &  resize_info,
const std::shared_ptr< const fml::SyncSwitch > &  gpu_disabled_switch 
)
static

Create a device private texture from the provided host buffer.

Parameters
resultThe image result closure that accepts the DlImage and any encoding error messages.
contextThe Impeller graphics context.
bufferA host buffer containing the image to be uploaded.
image_infoFormat information about the particular image.
bitmapA bitmap containg the image to be uploaded.
gpu_disabled_switchWhether the GPU is available command encoding.

Definition at line 428 of file image_decoder_impeller.cc.

435 {
436 TRACE_EVENT0("impeller", __FUNCTION__);
437 if (!context) {
438 result(nullptr, "No Impeller context is available");
439 return;
440 }
441 if (!buffer) {
442 result(nullptr, "No Impeller device buffer is available");
443 return;
444 }
445
446 gpu_disabled_switch->Execute(
448 .SetIfFalse([&result, context, buffer, image_info, resize_info] {
449 sk_sp<DlImage> image;
450 std::string decode_error;
451 std::tie(image, decode_error) = std::tie(image, decode_error) =
452 UnsafeUploadTextureToPrivate(context, buffer, image_info,
453 resize_info);
454 result(image, decode_error);
455 })
456 .SetIfTrue([&result, context, buffer, image_info, resize_info] {
457 auto result_ptr = std::make_shared<ImageResult>(std::move(result));
458 context->StoreTaskForGPU(
459 [result_ptr, context, buffer, image_info, resize_info]() {
460 sk_sp<DlImage> image;
461 std::string decode_error;
462 std::tie(image, decode_error) = UnsafeUploadTextureToPrivate(
463 context, buffer, image_info, resize_info);
464 (*result_ptr)(image, decode_error);
465 },
466 [result_ptr]() {
467 (*result_ptr)(
468 nullptr,
469 "Image upload failed due to loss of GPU access.");
470 });
471 }));
472}
Represents the 2 code paths available when calling |SyncSwitchExecute|.
Definition sync_switch.h:35

References flutter::buffer, image, and TRACE_EVENT0.

Referenced by flutter::testing::TEST_F(), and flutter::testing::TEST_F().

◆ UploadTextureToStorage()

std::pair< sk_sp< DlImage >, std::string > flutter::ImageDecoderImpeller::UploadTextureToStorage ( const std::shared_ptr< impeller::Context > &  context,
std::shared_ptr< SkBitmap >  bitmap 
)
static

Create a texture from the provided bitmap.

Parameters
contextThe Impeller graphics context.
bitmapA bitmap containg the image to be uploaded.
Returns
A DlImage.

Definition at line 475 of file image_decoder_impeller.cc.

477 {
478 TRACE_EVENT0("impeller", __FUNCTION__);
479 if (!context) {
480 return std::make_pair(nullptr, "No Impeller context is available");
481 }
482 if (!bitmap) {
483 return std::make_pair(nullptr, "No texture bitmap is available");
484 }
485 const auto image_info = bitmap->info();
486 const auto pixel_format = ToPixelFormat(image_info.colorType());
487 if (!pixel_format) {
488 std::string decode_error(
489 std::format("Unsupported pixel format (SkColorType={})",
490 static_cast<int>(image_info.colorType())));
491 FML_DLOG(ERROR) << decode_error;
492 return std::make_pair(nullptr, decode_error);
493 }
494
495 impeller::TextureDescriptor texture_descriptor;
497 texture_descriptor.format = pixel_format.value();
498 texture_descriptor.size = {image_info.width(), image_info.height()};
499 texture_descriptor.mip_count = 1;
500
501 auto texture =
502 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
503 if (!texture) {
504 std::string decode_error("Could not create Impeller texture.");
505 FML_DLOG(ERROR) << decode_error;
506 return std::make_pair(nullptr, decode_error);
507 }
508
509 auto mapping = std::make_shared<fml::NonOwnedMapping>(
510 reinterpret_cast<const uint8_t*>(bitmap->getAddr(0, 0)), // data
511 texture_descriptor.GetByteSizeOfBaseMipLevel(), // size
512 [bitmap](auto, auto) mutable { bitmap.reset(); } // proc
513 );
514
515 if (!texture->SetContents(mapping)) {
516 std::string decode_error("Could not copy contents into Impeller texture.");
517 FML_DLOG(ERROR) << decode_error;
518 return std::make_pair(nullptr, decode_error);
519 }
520
521 texture->SetLabel(
522 std::format("ui.Image({})", static_cast<const void*>(texture.get()))
523 .c_str());
524
525 context->DisposeThreadLocalCachedResources();
526
527 return std::make_pair(impeller::DlImageImpeller::Make(std::move(texture)),
528 std::string());
529}
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
FlTexture * texture
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const

References FML_DLOG, impeller::TextureDescriptor::format, impeller::TextureDescriptor::GetByteSizeOfBaseMipLevel(), impeller::kHostVisible, impeller::DlImageImpeller::Make(), impeller::TextureDescriptor::mip_count, impeller::TextureDescriptor::size, impeller::TextureDescriptor::storage_mode, texture, impeller::ToPixelFormat(), TRACE_EVENT0, and impeller::TSize< T >::width.

Referenced by flutter::testing::TEST_F().


The documentation for this class was generated from the following files: