1 /*
2 Software License :
3 
4 Copyright (c) 2012, The Open Effects Association Ltd. All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9     * Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright notice,
12       this list of conditions and the following disclaimer in the documentation
13       and/or other materials provided with the distribution.
14     * Neither the name The Open Effects Association Ltd, nor the names of its
15       contributors may be used to endorse or promote products derived from this
16       software without specific prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 
31 /*
32    Direct GPU processing using OpenGL
33  */
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <cuda.h>
38 #include <cuda_runtime_api.h>
39 
40 #include "ofxImageEffect.h"
41 #include "ofxMemory.h"
42 #include "ofxMultiThread.h"
43 
44 #include "ofxUtilities.H" // example support utils
45 
46 // pointers64 to various bits of the host
47 OfxHost               *gHost;
48 OfxImageEffectSuiteV1 *gEffectHost = 0;
49 OfxPropertySuiteV1    *gPropHost = 0;
50 OfxParameterSuiteV1   *gParamHost = 0;
51 OfxMemorySuiteV1      *gMemoryHost = 0;
52 OfxMultiThreadSuiteV1 *gThreadHost = 0;
53 OfxMessageSuiteV1     *gMessageSuite = 0;
54 OfxInteractSuiteV1    *gInteractHost = 0;
55 
56 // some flags about the host's behaviour
57 int gHostSupportsMultipleBitDepths = false;
58 int gHostSupportsCuda = false;
59 
60 #define CHECK_STATUS(args) check_status_fun args
61 
62 static void
check_status_fun(int status,int expected,const char * name)63 check_status_fun(int status, int expected, const char *name)
64 {
65   if (status != expected) {
66     fprintf(stderr, "OFX error in %s: expected status %d, got %d\n",
67 	    name, expected, status);
68   }
69 }
70 
71 #define DPRINT(args) print_dbg args
print_dbg(const char * fmt,...)72 void print_dbg(const char *fmt, ...)
73 {
74   char msg[1024];
75   va_list ap;
76 
77   va_start(ap, fmt);
78   vsnprintf(msg, 1023, fmt, ap);
79   fwrite(msg, sizeof(char), strlen(msg), stderr);
80   fflush(stderr);
81 #ifdef _WIN32
82   OutputDebugString(msg);
83 #endif
84   va_end(ap);
85 }
86 
87 // private instance data type
88 struct MyInstanceData {
89   bool isGeneralEffect;
90 
91   // handles to the clips we deal with
92   OfxImageClipHandle sourceClip;
93   OfxImageClipHandle outputClip;
94 
95   // handles to our parameters
96   OfxParamHandle rGainParam;
97   OfxParamHandle gGainParam;
98   OfxParamHandle bGainParam;
99 };
100 
101 /* mandatory function to set up the host structures */
102 
103 
104 // Convinience wrapper to get private data
105 static MyInstanceData *
getMyInstanceData(OfxImageEffectHandle effect)106 getMyInstanceData( OfxImageEffectHandle effect)
107 {
108   // get the property handle for the plugin
109   OfxPropertySetHandle effectProps;
110   gEffectHost->getPropertySet(effect, &effectProps);
111 
112   // get my data pointer out of that
113   MyInstanceData *myData = 0;
114   gPropHost->propGetPointer(effectProps,  kOfxPropInstanceData, 0,
115 			    (void **) &myData);
116   return myData;
117 }
118 
119 /** @brief Called at load */
120 static OfxStatus
onLoad(void)121 onLoad(void)
122 {
123   return kOfxStatOK;
124 }
125 
126 /** @brief Called before unload */
127 static OfxStatus
onUnLoad(void)128 onUnLoad(void)
129 {
130   return kOfxStatOK;
131 }
132 
133 //  instance construction
134 static OfxStatus
createInstance(OfxImageEffectHandle effect)135 createInstance( OfxImageEffectHandle effect)
136 {
137   // get a pointer to the effect properties
138   OfxPropertySetHandle effectProps;
139   gEffectHost->getPropertySet(effect, &effectProps);
140 
141   // get a pointer to the effect's parameter set
142   OfxParamSetHandle paramSet;
143   gEffectHost->getParamSet(effect, &paramSet);
144 
145   // make my private instance data
146   MyInstanceData *myData = new MyInstanceData;
147   const char *context = 0;
148 
149   // is this instance a general effect ?
150   gPropHost->propGetString(effectProps, kOfxImageEffectPropContext, 0,  &context);
151   myData->isGeneralEffect = context && (strcmp(context, kOfxImageEffectContextGeneral) == 0);
152 
153   // cache away our param handles
154   gParamHost->paramGetHandle(paramSet, "R Gain", &myData->rGainParam, 0);
155   gParamHost->paramGetHandle(paramSet, "G Gain", &myData->gGainParam, 0);
156   gParamHost->paramGetHandle(paramSet, "B Gain", &myData->bGainParam, 0);
157 
158   // cache away our clip handles
159   gEffectHost->clipGetHandle(effect, "Source", &myData->sourceClip, 0);
160   gEffectHost->clipGetHandle(effect, "Output", &myData->outputClip, 0);
161 
162   // set my private instance data
163   gPropHost->propSetPointer(effectProps, kOfxPropInstanceData, 0, (void *) myData);
164 
165   return kOfxStatOK;
166 }
167 
168 // instance destruction
169 static OfxStatus
destroyInstance(OfxImageEffectHandle effect)170 destroyInstance( OfxImageEffectHandle  effect)
171 {
172   // get my instance data
173   MyInstanceData *myData = getMyInstanceData(effect);
174 
175   // and delete it
176   if(myData)
177     delete myData;
178   return kOfxStatOK;
179 }
180 
181 // tells the host what region we are capable of filling
182 OfxStatus
getSpatialRoD(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)183 getSpatialRoD( OfxImageEffectHandle  effect,  OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
184 {
185   // retrieve any instance data associated with this effect
186   MyInstanceData *myData = getMyInstanceData(effect);
187 
188   OfxTime time;
189   gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
190 
191   // my RoD is the same as my input's
192   OfxRectD rod;
193   gEffectHost->clipGetRegionOfDefinition(myData->sourceClip, time, &rod);
194 
195   // set the rod in the out args
196   gPropHost->propSetDoubleN(outArgs, kOfxImageEffectPropRegionOfDefinition, 4, &rod.x1);
197 
198   return kOfxStatOK;
199 }
200 
201 // tells the host how much of the input we need to fill the given window
202 OfxStatus
getSpatialRoI(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)203 getSpatialRoI( OfxImageEffectHandle  effect,  OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
204 {
205   // get the RoI the effect is interested in from inArgs
206   OfxRectD roi;
207   gPropHost->propGetDoubleN(inArgs, kOfxImageEffectPropRegionOfInterest, 4, &roi.x1);
208 
209   // the input needed is the same as the output, so set that on the source clip
210   gPropHost->propSetDoubleN(outArgs, "OfxImageClipPropRoI_Source", 4, &roi.x1);
211 
212   // retrieve any instance data associated with this effect
213   MyInstanceData *myData = getMyInstanceData(effect);
214 
215   return kOfxStatOK;
216 }
217 
218 // Tells the host how many frames we can fill, only called in the general context.
219 // This is actually redundant as this is the default behaviour, but for illustrative
220 // purposes.
221 OfxStatus
getTemporalDomain(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)222 getTemporalDomain( OfxImageEffectHandle  effect,  OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
223 {
224   MyInstanceData *myData = getMyInstanceData(effect);
225 
226   double sourceRange[2];
227 
228   // get the frame range of the source clip
229   OfxPropertySetHandle props; gEffectHost->clipGetPropertySet(myData->sourceClip, &props);
230   gPropHost->propGetDoubleN(props, kOfxImageEffectPropFrameRange, 2, sourceRange);
231 
232   // set it on the out args
233   gPropHost->propSetDoubleN(outArgs, kOfxImageEffectPropFrameRange, 2, sourceRange);
234 
235   return kOfxStatOK;
236 }
237 
238 
239 // Set our clip preferences
240 static OfxStatus
getClipPreferences(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)241 getClipPreferences( OfxImageEffectHandle  effect,  OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
242 {
243   // retrieve any instance data associated with this effect
244   MyInstanceData *myData = getMyInstanceData(effect);
245 
246   // get the component type and bit depth of our main input
247   int  bitDepth;
248   bool isRGBA;
249   ofxuClipGetFormat(myData->sourceClip, bitDepth, isRGBA, true); // get the unmapped clip component
250 
251   // get the strings used to label the various bit depths
252   const char *bitDepthStr = bitDepth == 8 ? kOfxBitDepthByte : (bitDepth == 16 ? kOfxBitDepthShort : kOfxBitDepthFloat);
253   const char *componentStr = isRGBA ? kOfxImageComponentRGBA : kOfxImageComponentAlpha;
254 
255   // set out output to be the same same as the input, component and bitdepth
256   gPropHost->propSetString(outArgs, "OfxImageClipPropComponents_Output", 0, componentStr);
257   if(gHostSupportsMultipleBitDepths)
258     gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, bitDepthStr);
259 
260   return kOfxStatOK;
261 }
262 
263 // are the settings of the effect performing an identity operation
264 static OfxStatus
isIdentity(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)265 isIdentity( OfxImageEffectHandle  effect,
266 	    OfxPropertySetHandle inArgs,
267 	    OfxPropertySetHandle outArgs)
268 {
269   // In this case do the default, which in this case is to render
270   return kOfxStatReplyDefault;
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 // function called when the instance has been changed by anything
275 static OfxStatus
instanceChanged(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)276 instanceChanged( OfxImageEffectHandle  effect,
277 		 OfxPropertySetHandle inArgs,
278 		 OfxPropertySetHandle outArgs)
279 {
280   // don't trap any others
281   return kOfxStatReplyDefault;
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 // rendering routines
286 
287 extern void RunKernel(int p_Width, int p_Height, float p_RGain, float p_GGain, float p_BGain, float* p_Input, float* p_Output);
288 
289 // the process code  that the host sees
render(OfxImageEffectHandle instance,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)290 static OfxStatus render( OfxImageEffectHandle  instance,
291                          OfxPropertySetHandle inArgs,
292                          OfxPropertySetHandle outArgs)
293 {
294   // get the render window and the time from the inArgs
295   OfxTime time;
296   OfxRectI renderWindow;
297   OfxStatus status = kOfxStatOK;
298 
299   gPropHost->propGetDouble(inArgs, kOfxPropTime, 0, &time);
300   gPropHost->propGetIntN(inArgs, kOfxImageEffectPropRenderWindow, 4, &renderWindow.x1);
301 
302   // Retrieve instance data associated with this effect
303   MyInstanceData *myData = getMyInstanceData(instance);
304 
305   // property handles and members of each image
306   OfxPropertySetHandle sourceImg = NULL, outputImg = NULL;
307   int srcRowBytes, srcBitDepth, dstRowBytes, dstBitDepth;
308   bool srcIsAlpha, dstIsAlpha;
309   OfxRectI dstRect, srcRect;
310   void *src, *dst;
311 
312   DPRINT(("Render: window = [%d, %d - %d, %d]\n",
313 	  renderWindow.x1, renderWindow.y1,
314 	  renderWindow.x2, renderWindow.y2));
315 
316   int isCudaEnabled = 0;
317   if (gHostSupportsCuda)
318   {
319       gPropHost->propGetInt(inArgs, kOfxImageEffectPropCudaEnabled, 0, &isCudaEnabled);
320       DPRINT(("render: Cuda rendering %s\n", isCudaEnabled ? "enabled" : "DISABLED"));
321   }
322 
323   cudaError_t cudaError;
324   int deviceCount;
325 
326   cudaGetDeviceCount(&deviceCount);
327 
328   cudaDeviceProp deviceProp;
329   for (int i = 0; i < deviceCount; ++i)
330   {
331       cudaGetDeviceProperties(&deviceProp, i);
332       DPRINT(("Device [%d/%d] %s (Unified addressing %d)\n", i, deviceCount, deviceProp.name, deviceProp.unifiedAddressing));
333   }
334 
335   // Get the Cuda device that the host is running on
336   int hostDevice;
337   cudaGetDevice(&hostDevice);
338 
339   // Use the first Cuda device
340   int pluginDevice = 0;
341   cudaError = cudaSetDevice(pluginDevice);
342   if (cudaError != cudaSuccess)
343   {
344       DPRINT(("cudaSetDevice: cudaError %d\n", cudaError));
345   }
346 
347   cudaGetDeviceProperties(&deviceProp, pluginDevice);
348   DPRINT(("Using %s for plugin\n", deviceProp.name));
349 
350   // get the source image
351   sourceImg = ofxuGetImage(myData->sourceClip, time, srcRowBytes, srcBitDepth, srcIsAlpha, srcRect, src);
352 
353   // get the output image
354   outputImg = ofxuGetImage(myData->outputClip, time, dstRowBytes, dstBitDepth, dstIsAlpha, dstRect, dst);
355 
356   // get the scale parameter
357   double rGain = 1, gGain = 1, bGain = 1;
358   gParamHost->paramGetValueAtTime(myData->rGainParam, time, &rGain);
359   gParamHost->paramGetValueAtTime(myData->gGainParam, time, &gGain);
360   gParamHost->paramGetValueAtTime(myData->bGainParam, time, &bGain);
361   DPRINT(("Gain(%f %f %f)\n", rGain, gGain, bGain));
362 
363   float w = (renderWindow.x2 - renderWindow.x1);
364   float h = (renderWindow.y2 - renderWindow.y1);
365 
366   // Allocate the temporary buffers on the plugin device
367   void* inBuffer;
368   cudaError = cudaMalloc(&inBuffer, sizeof(float) * w * h * 4);
369   if (cudaError != cudaSuccess)
370   {
371       DPRINT(("cudaMalloc: cudaError %d\n", cudaError));
372   }
373   void* outBuffer;
374   cudaError = cudaMalloc(&outBuffer, sizeof(float) * w * h * 4);
375   if (cudaError != cudaSuccess)
376   {
377       DPRINT(("cudaMalloc: cudaError %d\n", cudaError));
378   }
379 
380   if (isCudaEnabled)
381   {
382       if (pluginDevice == hostDevice)
383       {
384           DPRINT(("Using Cuda transfers (same device)\n"));
385 
386           RunKernel(w, h, rGain, gGain, bGain, static_cast<float*>(src), static_cast<float*>(dst));
387 
388           if (cudaError != cudaSuccess)
389           {
390               DPRINT(("cudaMemcpy: cudaError %d\n", cudaError));
391           }
392       }
393       else
394       {
395         DPRINT(("Using Cuda transfers (different devices)\n"));
396 
397         // Copy the buffer from the host device to the plugin device
398         cudaError = cudaMemcpyPeer(inBuffer, pluginDevice, src, hostDevice, sizeof(float) * w * h * 4);
399 
400         if (cudaError != cudaSuccess)
401         {
402             DPRINT(("cudaMemcpyPeer: cudaError %d\n", cudaError));
403         }
404 
405         RunKernel(w, h, rGain, gGain, bGain, static_cast<float*>(inBuffer), static_cast<float*>(outBuffer));
406 
407         if (cudaError != cudaSuccess)
408         {
409             DPRINT(("cudaMemcpy: cudaError %d\n", cudaError));
410         }
411 
412 
413         // Copy the buffer from the plugin device to the host device
414         cudaError = cudaMemcpyPeer(dst, hostDevice, outBuffer, pluginDevice, sizeof(float) * w * h * 4);
415 
416         if (cudaError != cudaSuccess)
417         {
418             DPRINT(("cudaMemcpyPeer: cudaError %d\n", cudaError));
419         }
420       }
421   }
422   else
423   {
424       DPRINT(("Using CPU transfers\n"));
425 
426       // Copy the buffer from the CPU to the plugin device
427       cudaError = cudaMemcpy(inBuffer, src, sizeof(float) * w * h * 4, cudaMemcpyHostToDevice);
428 
429       if (cudaError != cudaSuccess)
430       {
431           DPRINT(("cudaMemcpy: cudaError %d\n", cudaError));
432       }
433 
434       RunKernel(w, h, rGain, gGain, bGain, static_cast<float*>(inBuffer), static_cast<float*>(outBuffer));
435 
436       if (cudaError != cudaSuccess)
437       {
438           DPRINT(("cudaMemcpy: cudaError %d\n", cudaError));
439       }
440 
441       // Copy the buffer from the plugin device to the CPU
442       cudaError = cudaMemcpy(dst, outBuffer, sizeof(float) * w * h * 4, cudaMemcpyDeviceToHost);
443 
444       if (cudaError != cudaSuccess)
445       {
446           DPRINT(("cudaMemcpy: cudaError %d\n", cudaError));
447       }
448   }
449 
450   // Free the temporary buffers on the plugin device
451   cudaFree(inBuffer);
452   cudaFree(outBuffer);
453 
454   // Set back the Cuda device that the host is running on
455   cudaSetDevice(hostDevice);
456 
457   if (sourceImg)
458   {
459       gEffectHost->clipReleaseImage(sourceImg);
460   }
461 
462   if (outputImg)
463   {
464       gEffectHost->clipReleaseImage(outputImg);
465   }
466 
467   return status;
468 }
469 
470 // convience function to define parameters
471 static void
defineParam(OfxParamSetHandle effectParams,const char * name,const char * label,const char * scriptName,const char * hint,const char * parent)472 defineParam( OfxParamSetHandle effectParams,
473 	     const char *name,
474 	     const char *label,
475 	     const char *scriptName,
476 	     const char *hint,
477 	     const char *parent)
478 {
479   OfxParamHandle param;
480   OfxPropertySetHandle props;
481   gParamHost->paramDefine(effectParams, kOfxParamTypeDouble, name, &props);
482 
483   // say we are a scaling parameter
484   gPropHost->propSetString(props, kOfxParamPropDoubleType, 0, kOfxParamDoubleTypeScale);
485   gPropHost->propSetDouble(props, kOfxParamPropDefault, 0, 1.0);
486   gPropHost->propSetDouble(props, kOfxParamPropMin, 0, 0.01);
487   gPropHost->propSetDouble(props, kOfxParamPropDisplayMin, 0, 0.01);
488   gPropHost->propSetDouble(props, kOfxParamPropDisplayMax, 0, 2.0);
489   gPropHost->propSetDouble(props, kOfxParamPropIncrement, 0, 0.01);
490   gPropHost->propSetString(props, kOfxParamPropHint, 0, hint);
491   gPropHost->propSetString(props, kOfxParamPropScriptName, 0, scriptName);
492   gPropHost->propSetString(props, kOfxPropLabel, 0, label);
493   if(parent)
494     gPropHost->propSetString(props, kOfxParamPropParent, 0, parent);
495 }
496 
497 //  describe the plugin in context
498 static OfxStatus
describeInContext(OfxImageEffectHandle effect,OfxPropertySetHandle inArgs)499 describeInContext( OfxImageEffectHandle  effect,  OfxPropertySetHandle inArgs)
500 {
501   // get the context from the inArgs handle
502   const char *context;
503   gPropHost->propGetString(inArgs, kOfxImageEffectPropContext, 0, &context);
504   bool isGeneralContext = strcmp(context, kOfxImageEffectContextGeneral) == 0;
505 
506   OfxPropertySetHandle props;
507   // define the single output clip in both contexts
508   gEffectHost->clipDefine(effect, "Output", &props);
509 
510   // set the component types we can handle on out output
511   gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
512   gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
513 
514   // define the single source clip in both contexts
515   gEffectHost->clipDefine(effect, "Source", &props);
516 
517   // set the component types we can handle on our main input
518   gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 0, kOfxImageComponentRGBA);
519   gPropHost->propSetString(props, kOfxImageEffectPropSupportedComponents, 1, kOfxImageComponentAlpha);
520 
521   ////////////////////////////////////////////////////////////////////////////////
522   // define the parameters for this context
523   // fetch the parameter set from the effect
524   OfxParamSetHandle paramSet;
525   gEffectHost->getParamSet(effect, &paramSet);
526 
527   defineParam(paramSet, "R Gain", "R Gain", "R Gain",
528           "Red Gain", 0);
529   defineParam(paramSet, "G Gain", "G Gain", "G Gain",
530           "Green Gain", 0);
531   defineParam(paramSet, "B Gain", "B Gain", "B Gain",
532           "Blue Gain", 0);
533 
534   // make a page of controls and add my parameters to it
535   OfxParamHandle page;
536   gParamHost->paramDefine(paramSet, kOfxParamTypePage, "Main", &props);
537   gPropHost->propSetString(props, kOfxParamPropPageChild, 0, "R Gain");
538   gPropHost->propSetString(props, kOfxParamPropPageChild, 1, "G Gain");
539   gPropHost->propSetString(props, kOfxParamPropPageChild, 2, "B Gain");
540   return kOfxStatOK;
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 // the plugin's description routine
545 static OfxStatus
describe(OfxImageEffectHandle effect)546 describe(OfxImageEffectHandle  effect)
547 {
548   // first fetch the host APIs, this cannot be done before this call
549   OfxStatus stat;
550   if((stat = ofxuFetchHostSuites()) != kOfxStatOK)
551     return stat;
552 
553   // record a few host features
554   gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &gHostSupportsMultipleBitDepths);
555 
556   // get the property handle for the plugin
557   OfxPropertySetHandle effectProps;
558   gEffectHost->getPropertySet(effect, &effectProps);
559 
560   // We can render both fields in a fielded images in one hit if there is no animation
561   // So set the flag that allows us to do this
562   gPropHost->propSetInt(effectProps, kOfxImageEffectPluginPropFieldRenderTwiceAlways, 0, 0);
563 
564   // say we can support multiple pixel depths and let the clip preferences action deal with it all.
565   gPropHost->propSetInt(effectProps, kOfxImageEffectPropSupportsMultipleClipDepths, 0, 1);
566 
567   // set the bit depths the plugin can handle
568   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 0, kOfxBitDepthByte);
569   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 1, kOfxBitDepthShort);
570   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedPixelDepths, 2, kOfxBitDepthFloat);
571 
572   // set some labels and the group it belongs to
573   gPropHost->propSetString(effectProps, kOfxPropLabel, 0, "Resolve Simple Gain (CUDA)");
574   gPropHost->propSetString(effectProps, kOfxImageEffectPluginPropGrouping, 0, "Resolve Simple Gain");
575 
576   // define the contexts we can be used in
577   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 0, kOfxImageEffectContextFilter);
578   gPropHost->propSetString(effectProps, kOfxImageEffectPropSupportedContexts, 1, kOfxImageEffectContextGeneral);
579 
580   // we support Cuda rendering
581   gPropHost->propSetString(effectProps, kOfxImageEffectPropCudaRenderSupported, 0, "true");
582 
583   {
584     const char *s = "<undefined>";
585     stat = gPropHost->propGetString(gHost->host, kOfxImageEffectPropCudaRenderSupported, 0, &s);
586     DPRINT(("Host has Cuda render support: %s (stat=%d)\n", s, stat));
587     gHostSupportsCuda = stat == 0 && !strcmp(s, "true");
588   }
589 
590   return kOfxStatOK;
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 // The main function
595 static OfxStatus
pluginMain(const char * action,const void * handle,OfxPropertySetHandle inArgs,OfxPropertySetHandle outArgs)596 pluginMain(const char *action,  const void *handle, OfxPropertySetHandle inArgs,  OfxPropertySetHandle outArgs)
597 {
598   // cast to appropriate type
599   OfxImageEffectHandle effect = (OfxImageEffectHandle) handle;
600 
601   if(strcmp(action, kOfxActionDescribe) == 0) {
602     return describe(effect);
603   }
604   else if(strcmp(action, kOfxImageEffectActionDescribeInContext) == 0) {
605     return describeInContext(effect, inArgs);
606   }
607   else if(strcmp(action, kOfxActionLoad) == 0) {
608     return onLoad();
609   }
610   else if(strcmp(action, kOfxActionUnload) == 0) {
611     return onUnLoad();
612   }
613   else if(strcmp(action, kOfxActionCreateInstance) == 0) {
614     return createInstance(effect);
615   }
616   else if(strcmp(action, kOfxActionDestroyInstance) == 0) {
617     return destroyInstance(effect);
618   }
619   else if(strcmp(action, kOfxImageEffectActionIsIdentity) == 0) {
620     return isIdentity(effect, inArgs, outArgs);
621   }
622   else if(strcmp(action, kOfxImageEffectActionRender) == 0) {
623     return render(effect, inArgs, outArgs);
624   }
625   else if(strcmp(action, kOfxImageEffectActionGetRegionOfDefinition) == 0) {
626     return getSpatialRoD(effect, inArgs, outArgs);
627   }
628   else if(strcmp(action, kOfxImageEffectActionGetRegionsOfInterest) == 0) {
629     return getSpatialRoI(effect, inArgs, outArgs);
630   }
631   else if(strcmp(action, kOfxImageEffectActionGetClipPreferences) == 0) {
632     return getClipPreferences(effect, inArgs, outArgs);
633   }
634   else if(strcmp(action, kOfxActionInstanceChanged) == 0) {
635     return instanceChanged(effect, inArgs, outArgs);
636   }
637   else if(strcmp(action, kOfxImageEffectActionGetTimeDomain) == 0) {
638     return getTemporalDomain(effect, inArgs, outArgs);
639   }
640 
641 
642   // other actions to take the default value
643   return kOfxStatReplyDefault;
644 }
645 
646 // function to set the host structure
647 static void
setHostFunc(OfxHost * hostStruct)648 setHostFunc(OfxHost *hostStruct)
649 {
650   gHost         = hostStruct;
651 }
652 
653 ////////////////////////////////////////////////////////////////////////////////
654 // the plugin struct
655 static OfxPlugin basicPlugin =
656 {
657   kOfxImageEffectPluginApi,
658   1,
659   "com.blackmagicdesign.ResolveSimpleGainCUDAPlugin",
660   1,
661   0,
662   setHostFunc,
663   pluginMain
664 };
665 
666 // the two mandated functions
667 OfxPlugin *
OfxGetPlugin(int nth)668 OfxGetPlugin(int nth)
669 {
670   if(nth == 0)
671     return &basicPlugin;
672   return 0;
673 }
674 
675 int
OfxGetNumberOfPlugins(void)676 OfxGetNumberOfPlugins(void)
677 {
678   return 1;
679 }
680