1 module oclcv.morphed;
2 
3 import oclcv.clcore;
4 
5 import dplug.core.nogc;
6 import bc.string;
7 
8 alias MORPH_OP = int;
9 enum : MORPH_OP {
10     ERODE,
11     DILATE
12 }
13 
14 final class MorphED {
15 public:
16 @nogc nothrow:
17     this(int height, int width, MORPH_OP op, int kernelSize, CLContext ctx){
18 
19         width_ = width; height_= height; _op = op; kernelSize_ = kernelSize;
20 
21         initialize(ctx);
22     }
23 
24     ~this(){
25         destroyFree(prog_);
26     }
27 
28     private bool initialize(CLContext ctx){
29         if(!ctx)
30             return false;
31         context_ = ctx;
32 
33         tile_w = width_;
34         tile_h = 1;
35 
36         block2 = BlockDim(tile_w + (2 * kernelSize_), tile_h);
37 
38         import std.conv : to;
39 
40         auto compilerParam = RCStringZ.from(nogcFormat!"-D %s -D SHARED_SIZE=%d -D radio=%d"(
41             ((_op==ERODE)?"ERODE":"DILATE"), block2.y*block2.x, kernelSize_ ));
42         prog_ = mallocNew!CLProgram(CTKernel.KMORPHED, context_, compilerParam[]);
43         
44         _kernel_step1 = prog_.getKernel("morphSharedStep1");
45         _kernel_step2 = prog_.getKernel("morphSharedStep2");
46         
47         return true;
48     }
49     
50     CLBuffer run(CLBuffer d_src_mono, CLBuffer ownedBuffer = null){
51 
52         import core.stdc.math : ceil;
53 
54         debug _assert(d_src_mono.metaData.dataType == UBYTE, "Input type must be ubyte"); 
55         debug _assert(d_src_mono.metaData.numberOfChannels == 1, "Input's channel count must be 1");
56 
57         CLBuffer d_output;
58         if(ownedBuffer is null){
59             d_output = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 1));
60         } else {
61             d_output = ownedBuffer;
62         }
63          
64         CLBuffer d_tmp = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 1));
65 
66         tile_w = width_;
67         tile_h = 1;
68 
69         block2 = BlockDim(tile_w + (2 * kernelSize_), tile_h);
70         
71         _kernel_step1.setArgs(d_src_mono, d_tmp, width_, height_, tile_w, tile_h);
72         
73         _kernel_step1.launch(0, GridDim(cast(int)ceil(cast(float)width_ / tile_w), 
74                                   cast(int)ceil(cast(float)height_ / tile_h)),
75                                   block2);
76         context_.finish(0);
77 
78         tile_w = 8;
79         tile_h = 64;
80 
81         _kernel_step2.setArgs(d_tmp, d_output, width_, height_, tile_w, tile_h);
82         
83         _kernel_step2.launch(0, 
84             GridDim(cast(int)ceil(cast(float)width_ / tile_w), cast(int)ceil(cast(float)height_ / tile_h)),
85                         BlockDim(tile_w, tile_h + (2 * kernelSize_)));
86         context_.finish(0);
87 
88         destroyFree(d_tmp);
89         
90         return d_output;
91     }
92 
93 private:
94     int width_, height_;
95     int kernelSize_;
96     int tile_w;
97     int tile_h;
98     BlockDim block2;
99     CLContext context_;
100     CLProgram prog_;
101     
102     CLKernel _kernel_step1;
103     CLKernel _kernel_step2;
104     MORPH_OP _op;
105 }