Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / cc / resources / resource_provider.h
1 // Copyright 2012 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 #ifndef CC_RESOURCES_RESOURCE_PROVIDER_H_
6 #define CC_RESOURCES_RESOURCE_PROVIDER_H_
7
8 #include <deque>
9 #include <set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/basictypes.h"
15 #include "base/callback.h"
16 #include "base/containers/hash_tables.h"
17 #include "base/memory/linked_ptr.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/threading/thread_checker.h"
20 #include "cc/base/cc_export.h"
21 #include "cc/output/context_provider.h"
22 #include "cc/output/output_surface.h"
23 #include "cc/resources/release_callback_impl.h"
24 #include "cc/resources/resource_format.h"
25 #include "cc/resources/return_callback.h"
26 #include "cc/resources/shared_bitmap.h"
27 #include "cc/resources/single_release_callback_impl.h"
28 #include "cc/resources/texture_mailbox.h"
29 #include "cc/resources/transferable_resource.h"
30 #include "third_party/khronos/GLES2/gl2.h"
31 #include "third_party/khronos/GLES2/gl2ext.h"
32 #include "third_party/skia/include/core/SkBitmap.h"
33 #include "third_party/skia/include/core/SkCanvas.h"
34 #include "ui/gfx/geometry/size.h"
35
36 class GrContext;
37
38 namespace gpu {
39 class GpuMemoryBufferManager;
40 namespace gles {
41 class GLES2Interface;
42 }
43 }
44
45 namespace gfx {
46 class GpuMemoryBuffer;
47 class Rect;
48 class Vector2d;
49 }
50
51 namespace cc {
52 class BlockingTaskRunner;
53 class IdAllocator;
54 class SharedBitmap;
55 class SharedBitmapManager;
56 class TextureUploader;
57
58 // This class is not thread-safe and can only be called from the thread it was
59 // created on (in practice, the impl thread).
60 class CC_EXPORT ResourceProvider {
61  private:
62   struct Resource;
63
64  public:
65   typedef unsigned ResourceId;
66   typedef std::vector<ResourceId> ResourceIdArray;
67   typedef std::set<ResourceId> ResourceIdSet;
68   typedef base::hash_map<ResourceId, ResourceId> ResourceIdMap;
69   enum TextureHint {
70     TextureHintDefault = 0x0,
71     TextureHintImmutable = 0x1,
72     TextureHintFramebuffer = 0x2,
73     TextureHintImmutableFramebuffer =
74         TextureHintImmutable | TextureHintFramebuffer
75   };
76   enum ResourceType {
77     InvalidType = 0,
78     GLTexture = 1,
79     Bitmap,
80   };
81
82   static scoped_ptr<ResourceProvider> Create(
83       OutputSurface* output_surface,
84       SharedBitmapManager* shared_bitmap_manager,
85       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
86       BlockingTaskRunner* blocking_main_thread_task_runner,
87       int highp_threshold_min,
88       bool use_rgba_4444_texture_format,
89       size_t id_allocation_chunk_size);
90   virtual ~ResourceProvider();
91
92   void InitializeSoftware();
93   void InitializeGL();
94
95   void DidLoseOutputSurface() { lost_output_surface_ = true; }
96
97   int max_texture_size() const { return max_texture_size_; }
98   ResourceFormat memory_efficient_texture_format() const {
99     return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
100   }
101   ResourceFormat best_texture_format() const { return best_texture_format_; }
102   bool use_sync_query() const { return use_sync_query_; }
103   size_t num_resources() const { return resources_.size(); }
104
105   // Checks whether a resource is in use by a consumer.
106   bool InUseByConsumer(ResourceId id);
107
108   bool IsLost(ResourceId id);
109   bool AllowOverlay(ResourceId id);
110
111   // Producer interface.
112
113   ResourceType default_resource_type() const { return default_resource_type_; }
114   ResourceType GetResourceType(ResourceId id);
115
116   // Creates a resource of the default resource type.
117   ResourceId CreateResource(const gfx::Size& size,
118                             GLint wrap_mode,
119                             TextureHint hint,
120                             ResourceFormat format);
121
122   // Creates a resource which is tagged as being managed for GPU memory
123   // accounting purposes.
124   ResourceId CreateManagedResource(const gfx::Size& size,
125                                    GLenum target,
126                                    GLint wrap_mode,
127                                    TextureHint hint,
128                                    ResourceFormat format);
129
130   // You can also explicitly create a specific resource type.
131   ResourceId CreateGLTexture(const gfx::Size& size,
132                              GLenum target,
133                              GLenum texture_pool,
134                              GLint wrap_mode,
135                              TextureHint hint,
136                              ResourceFormat format);
137
138   ResourceId CreateBitmap(const gfx::Size& size, GLint wrap_mode);
139   // Wraps an IOSurface into a GL resource.
140   ResourceId CreateResourceFromIOSurface(const gfx::Size& size,
141                                          unsigned io_surface_id);
142
143   // Wraps an external texture mailbox into a GL resource.
144   ResourceId CreateResourceFromTextureMailbox(
145       const TextureMailbox& mailbox,
146       scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl);
147
148   void DeleteResource(ResourceId id);
149
150   // Update pixels from image, copying source_rect (in image) to dest_offset (in
151   // the resource).
152   void SetPixels(ResourceId id,
153                  const uint8_t* image,
154                  const gfx::Rect& image_rect,
155                  const gfx::Rect& source_rect,
156                  const gfx::Vector2d& dest_offset);
157
158   // Check upload status.
159   size_t NumBlockingUploads();
160   void MarkPendingUploadsAsNonBlocking();
161   size_t EstimatedUploadsPerTick();
162   void FlushUploads();
163   void ReleaseCachedData();
164   base::TimeTicks EstimatedUploadCompletionTime(size_t uploads_per_tick);
165
166   // Only flush the command buffer if supported.
167   // Returns true if the shallow flush occurred, false otherwise.
168   bool ShallowFlushIfSupported();
169
170   // Creates accounting for a child. Returns a child ID.
171   int CreateChild(const ReturnCallback& return_callback);
172
173   // Destroys accounting for the child, deleting all accounted resources.
174   void DestroyChild(int child);
175
176   // Gets the child->parent resource ID map.
177   const ResourceIdMap& GetChildToParentMap(int child) const;
178
179   // Prepares resources to be transfered to the parent, moving them to
180   // mailboxes and serializing meta-data into TransferableResources.
181   // Resources are not removed from the ResourceProvider, but are marked as
182   // "in use".
183   void PrepareSendToParent(const ResourceIdArray& resources,
184                            TransferableResourceArray* transferable_resources);
185
186   // Receives resources from a child, moving them from mailboxes. Resource IDs
187   // passed are in the child namespace, and will be translated to the parent
188   // namespace, added to the child->parent map.
189   // This adds the resources to the working set in the ResourceProvider without
190   // declaring which resources are in use. Use DeclareUsedResourcesFromChild
191   // after calling this method to do that. All calls to ReceiveFromChild should
192   // be followed by a DeclareUsedResourcesFromChild.
193   // NOTE: if the sync_point is set on any TransferableResource, this will
194   // wait on it.
195   void ReceiveFromChild(
196       int child, const TransferableResourceArray& transferable_resources);
197
198   // Once a set of resources have been received, they may or may not be used.
199   // This declares what set of resources are currently in use from the child,
200   // releasing any other resources back to the child.
201   void DeclareUsedResourcesFromChild(
202       int child,
203       const ResourceIdArray& resources_from_child);
204
205   // Receives resources from the parent, moving them from mailboxes. Resource
206   // IDs passed are in the child namespace.
207   // NOTE: if the sync_point is set on any TransferableResource, this will
208   // wait on it.
209   void ReceiveReturnsFromParent(
210       const ReturnedResourceArray& transferable_resources);
211
212   // The following lock classes are part of the ResourceProvider API and are
213   // needed to read and write the resource contents. The user must ensure
214   // that they only use GL locks on GL resources, etc, and this is enforced
215   // by assertions.
216   class CC_EXPORT ScopedReadLockGL {
217    public:
218     ScopedReadLockGL(ResourceProvider* resource_provider,
219                      ResourceProvider::ResourceId resource_id);
220     virtual ~ScopedReadLockGL();
221
222     unsigned texture_id() const { return texture_id_; }
223
224    protected:
225     ResourceProvider* resource_provider_;
226     ResourceProvider::ResourceId resource_id_;
227
228    private:
229     unsigned texture_id_;
230
231     DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL);
232   };
233
234   class CC_EXPORT ScopedSamplerGL : public ScopedReadLockGL {
235    public:
236     ScopedSamplerGL(ResourceProvider* resource_provider,
237                     ResourceProvider::ResourceId resource_id,
238                     GLenum filter);
239     ScopedSamplerGL(ResourceProvider* resource_provider,
240                     ResourceProvider::ResourceId resource_id,
241                     GLenum unit,
242                     GLenum filter);
243     ~ScopedSamplerGL() override;
244
245     GLenum target() const { return target_; }
246
247    private:
248     GLenum unit_;
249     GLenum target_;
250
251     DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL);
252   };
253
254   class CC_EXPORT ScopedWriteLockGL {
255    public:
256     ScopedWriteLockGL(ResourceProvider* resource_provider,
257                       ResourceProvider::ResourceId resource_id);
258     ~ScopedWriteLockGL();
259
260     unsigned texture_id() const { return texture_id_; }
261
262    private:
263     ResourceProvider* resource_provider_;
264     ResourceProvider::Resource* resource_;
265     unsigned texture_id_;
266
267     DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGL);
268   };
269
270   class CC_EXPORT ScopedReadLockSoftware {
271    public:
272     ScopedReadLockSoftware(ResourceProvider* resource_provider,
273                            ResourceProvider::ResourceId resource_id);
274     ~ScopedReadLockSoftware();
275
276     const SkBitmap* sk_bitmap() const {
277       DCHECK(valid());
278       return &sk_bitmap_;
279     }
280     GLint wrap_mode() const { return wrap_mode_; }
281
282     bool valid() const { return !!sk_bitmap_.getPixels(); }
283
284    private:
285     ResourceProvider* resource_provider_;
286     ResourceProvider::ResourceId resource_id_;
287     SkBitmap sk_bitmap_;
288     GLint wrap_mode_;
289
290     DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware);
291   };
292
293   class CC_EXPORT ScopedWriteLockSoftware {
294    public:
295     ScopedWriteLockSoftware(ResourceProvider* resource_provider,
296                             ResourceProvider::ResourceId resource_id);
297     ~ScopedWriteLockSoftware();
298
299     SkCanvas* sk_canvas() { return sk_canvas_.get(); }
300     bool valid() const { return !!sk_bitmap_.getPixels(); }
301
302    private:
303     ResourceProvider* resource_provider_;
304     ResourceProvider::Resource* resource_;
305     SkBitmap sk_bitmap_;
306     scoped_ptr<SkCanvas> sk_canvas_;
307     base::ThreadChecker thread_checker_;
308
309     DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware);
310   };
311
312   class CC_EXPORT ScopedWriteLockGpuMemoryBuffer {
313    public:
314     ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
315                                    ResourceProvider::ResourceId resource_id);
316     ~ScopedWriteLockGpuMemoryBuffer();
317
318     gfx::GpuMemoryBuffer* GetGpuMemoryBuffer();
319
320    private:
321     ResourceProvider* resource_provider_;
322     ResourceProvider::Resource* resource_;
323     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
324     gfx::GpuMemoryBuffer* gpu_memory_buffer_;
325     gfx::Size size_;
326     ResourceFormat format_;
327     base::ThreadChecker thread_checker_;
328
329     DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGpuMemoryBuffer);
330   };
331
332   class CC_EXPORT ScopedWriteLockGr {
333    public:
334     ScopedWriteLockGr(ResourceProvider* resource_provider,
335                       ResourceProvider::ResourceId resource_id);
336     ~ScopedWriteLockGr();
337
338     SkSurface* GetSkSurface(bool use_distance_field_text);
339
340    private:
341     ResourceProvider* resource_provider_;
342     ResourceProvider::Resource* resource_;
343     base::ThreadChecker thread_checker_;
344
345     DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGr);
346   };
347
348   class Fence : public base::RefCounted<Fence> {
349    public:
350     Fence() {}
351
352     virtual void Set() = 0;
353     virtual bool HasPassed() = 0;
354     virtual void Wait() = 0;
355
356    protected:
357     friend class base::RefCounted<Fence>;
358     virtual ~Fence() {}
359
360    private:
361     DISALLOW_COPY_AND_ASSIGN(Fence);
362   };
363
364   class SynchronousFence : public ResourceProvider::Fence {
365    public:
366     explicit SynchronousFence(gpu::gles2::GLES2Interface* gl);
367
368     // Overridden from Fence:
369     void Set() override;
370     bool HasPassed() override;
371     void Wait() override;
372
373     // Returns true if fence has been set but not yet synchornized.
374     bool has_synchronized() const { return has_synchronized_; }
375
376    private:
377     ~SynchronousFence() override;
378
379     void Synchronize();
380
381     gpu::gles2::GLES2Interface* gl_;
382     bool has_synchronized_;
383
384     DISALLOW_COPY_AND_ASSIGN(SynchronousFence);
385   };
386
387   // Acquire pixel buffer for resource. The pixel buffer can be used to
388   // set resource pixels without performing unnecessary copying.
389   void AcquirePixelBuffer(ResourceId resource);
390   void ReleasePixelBuffer(ResourceId resource);
391   // Map/unmap the acquired pixel buffer.
392   uint8_t* MapPixelBuffer(ResourceId id, int* stride);
393   void UnmapPixelBuffer(ResourceId id);
394   // Asynchronously update pixels from acquired pixel buffer.
395   void BeginSetPixels(ResourceId id);
396   void ForceSetPixelsToComplete(ResourceId id);
397   bool DidSetPixelsComplete(ResourceId id);
398
399   // For tests only! This prevents detecting uninitialized reads.
400   // Use SetPixels or LockForWrite to allocate implicitly.
401   void AllocateForTesting(ResourceId id);
402
403   // For tests only!
404   void CreateForTesting(ResourceId id);
405
406   GLenum TargetForTesting(ResourceId id);
407
408   // Sets the current read fence. If a resource is locked for read
409   // and has read fences enabled, the resource will not allow writes
410   // until this fence has passed.
411   void SetReadLockFence(Fence* fence) { current_read_lock_fence_ = fence; }
412
413   // Indicates if we can currently lock this resource for write.
414   bool CanLockForWrite(ResourceId id);
415
416   // Copy pixels from source to destination.
417   void CopyResource(ResourceId source_id, ResourceId dest_id);
418
419   void WaitSyncPointIfNeeded(ResourceId id);
420
421   void WaitReadLockIfNeeded(ResourceId id);
422
423   static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl);
424
425  private:
426   struct Resource {
427     enum Origin { Internal, External, Delegated };
428
429     Resource();
430     ~Resource();
431     Resource(unsigned texture_id,
432              const gfx::Size& size,
433              Origin origin,
434              GLenum target,
435              GLenum filter,
436              GLenum texture_pool,
437              GLint wrap_mode,
438              TextureHint hint,
439              ResourceFormat format);
440     Resource(uint8_t* pixels,
441              SharedBitmap* bitmap,
442              const gfx::Size& size,
443              Origin origin,
444              GLenum filter,
445              GLint wrap_mode);
446     Resource(const SharedBitmapId& bitmap_id,
447              const gfx::Size& size,
448              Origin origin,
449              GLenum filter,
450              GLint wrap_mode);
451
452     int child_id;
453     unsigned gl_id;
454     // Pixel buffer used for set pixels without unnecessary copying.
455     unsigned gl_pixel_buffer_id;
456     // Query used to determine when asynchronous set pixels complete.
457     unsigned gl_upload_query_id;
458     // Query used to determine when read lock fence has passed.
459     unsigned gl_read_lock_query_id;
460     TextureMailbox mailbox;
461     ReleaseCallbackImpl release_callback_impl;
462     uint8_t* pixels;
463     int lock_for_read_count;
464     int imported_count;
465     int exported_count;
466     bool dirty_image : 1;
467     bool locked_for_write : 1;
468     bool lost : 1;
469     bool marked_for_deletion : 1;
470     bool pending_set_pixels : 1;
471     bool set_pixels_completion_forced : 1;
472     bool allocated : 1;
473     bool read_lock_fences_enabled : 1;
474     bool has_shared_bitmap_id : 1;
475     bool allow_overlay : 1;
476     scoped_refptr<Fence> read_lock_fence;
477     gfx::Size size;
478     Origin origin;
479     GLenum target;
480     // TODO(skyostil): Use a separate sampler object for filter state.
481     GLenum original_filter;
482     GLenum filter;
483     unsigned image_id;
484     unsigned bound_image_id;
485     GLenum texture_pool;
486     GLint wrap_mode;
487     TextureHint hint;
488     ResourceType type;
489     ResourceFormat format;
490     SharedBitmapId shared_bitmap_id;
491     SharedBitmap* shared_bitmap;
492     gfx::GpuMemoryBuffer* gpu_memory_buffer;
493     skia::RefPtr<SkSurface> sk_surface;
494   };
495   typedef base::hash_map<ResourceId, Resource> ResourceMap;
496
497   static bool CompareResourceMapIteratorsByChildId(
498       const std::pair<ReturnedResource, ResourceMap::iterator>& a,
499       const std::pair<ReturnedResource, ResourceMap::iterator>& b);
500
501   struct Child {
502     Child();
503     ~Child();
504
505     ResourceIdMap child_to_parent_map;
506     ResourceIdMap parent_to_child_map;
507     ReturnCallback return_callback;
508     ResourceIdSet in_use_resources;
509     bool marked_for_deletion;
510   };
511   typedef base::hash_map<int, Child> ChildMap;
512
513   bool ReadLockFenceHasPassed(const Resource* resource) {
514     return !resource->read_lock_fence.get() ||
515            resource->read_lock_fence->HasPassed();
516   }
517
518   ResourceProvider(OutputSurface* output_surface,
519                    SharedBitmapManager* shared_bitmap_manager,
520                    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
521                    BlockingTaskRunner* blocking_main_thread_task_runner,
522                    int highp_threshold_min,
523                    bool use_rgba_4444_texture_format,
524                    size_t id_allocation_chunk_size);
525
526   void CleanUpGLIfNeeded();
527
528   Resource* GetResource(ResourceId id);
529   const Resource* LockForRead(ResourceId id);
530   void UnlockForRead(ResourceId id);
531   Resource* LockForWrite(ResourceId id);
532   void UnlockForWrite(Resource* resource);
533
534   static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
535                                            const Resource* resource);
536
537   void TransferResource(gpu::gles2::GLES2Interface* gl,
538                         ResourceId id,
539                         TransferableResource* resource);
540   enum DeleteStyle {
541     Normal,
542     ForShutdown,
543   };
544   void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style);
545   void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it,
546                                              DeleteStyle style,
547                                              const ResourceIdArray& unused);
548   void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style);
549   void LazyCreate(Resource* resource);
550   void LazyAllocate(Resource* resource);
551
552   void BindImageForSampling(Resource* resource);
553   // Binds the given GL resource to a texture target for sampling using the
554   // specified filter for both minification and magnification. Returns the
555   // texture target used. The resource must be locked for reading.
556   GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter);
557
558   // Returns NULL if the output_surface_ does not have a ContextProvider.
559   gpu::gles2::GLES2Interface* ContextGL() const;
560   class GrContext* GrContext() const;
561
562   OutputSurface* output_surface_;
563   SharedBitmapManager* shared_bitmap_manager_;
564   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
565   BlockingTaskRunner* blocking_main_thread_task_runner_;
566   bool lost_output_surface_;
567   int highp_threshold_min_;
568   ResourceId next_id_;
569   ResourceMap resources_;
570   int next_child_;
571   ChildMap children_;
572
573   ResourceType default_resource_type_;
574   bool use_texture_storage_ext_;
575   bool use_texture_format_bgra_;
576   bool use_texture_usage_hint_;
577   bool use_compressed_texture_etc1_;
578   scoped_ptr<TextureUploader> texture_uploader_;
579   int max_texture_size_;
580   ResourceFormat best_texture_format_;
581
582   base::ThreadChecker thread_checker_;
583
584   scoped_refptr<Fence> current_read_lock_fence_;
585   bool use_rgba_4444_texture_format_;
586
587   const size_t id_allocation_chunk_size_;
588   scoped_ptr<IdAllocator> texture_id_allocator_;
589   scoped_ptr<IdAllocator> buffer_id_allocator_;
590
591   bool use_sync_query_;
592   // Fence used for CopyResource if CHROMIUM_sync_query is not supported.
593   scoped_refptr<SynchronousFence> synchronous_fence_;
594
595   DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
596 };
597
598
599 // TODO(epenner): Move these format conversions to resource_format.h
600 // once that builds on mac (npapi.h currently #includes OpenGL.h).
601 inline unsigned BitsPerPixel(ResourceFormat format) {
602   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
603   static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = {
604     32,  // RGBA_8888
605     16,  // RGBA_4444
606     32,  // BGRA_8888
607     8,   // ALPHA_8
608     8,   // LUMINANCE_8
609     16,  // RGB_565,
610     4    // ETC1
611   };
612   return format_bits_per_pixel[format];
613 }
614
615 inline GLenum GLDataType(ResourceFormat format) {
616   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
617   static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
618     GL_UNSIGNED_BYTE,           // RGBA_8888
619     GL_UNSIGNED_SHORT_4_4_4_4,  // RGBA_4444
620     GL_UNSIGNED_BYTE,           // BGRA_8888
621     GL_UNSIGNED_BYTE,           // ALPHA_8
622     GL_UNSIGNED_BYTE,           // LUMINANCE_8
623     GL_UNSIGNED_SHORT_5_6_5,    // RGB_565,
624     GL_UNSIGNED_BYTE            // ETC1
625   };
626   return format_gl_data_type[format];
627 }
628
629 inline GLenum GLDataFormat(ResourceFormat format) {
630   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
631   static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
632     GL_RGBA,           // RGBA_8888
633     GL_RGBA,           // RGBA_4444
634     GL_BGRA_EXT,       // BGRA_8888
635     GL_ALPHA,          // ALPHA_8
636     GL_LUMINANCE,      // LUMINANCE_8
637     GL_RGB,            // RGB_565
638     GL_ETC1_RGB8_OES   // ETC1
639   };
640   return format_gl_data_format[format];
641 }
642
643 inline GLenum GLInternalFormat(ResourceFormat format) {
644   return GLDataFormat(format);
645 }
646
647 }  // namespace cc
648
649 #endif  // CC_RESOURCES_RESOURCE_PROVIDER_H_