//+------------------------------------------------------------------+ //| BufferDouble.mqh | //| AnimateDread | //| https://www.mql5.com | //+------------------------------------------------------------------+ //| CBufferDouble - the OpenCL/DirectML-backed buffer wrapper every | //| *OCL neuron class (AI\Network.mqh) uses for its weights/output/ | //| gradient storage. Needs COpenCLMy (AI\Network.mqh) and | //| CDirectMLMy (AI\NeuronDirectML.mqh) already declared. Extracted | //| verbatim out of AI\Network.mqh (SOLID cleanup) - no logic changes.| //+------------------------------------------------------------------+ #include "NeuronDirectML.mqh" class CBufferDouble : public CArrayDouble { protected: COpenCLMy *OpenCL; CDirectMLMy *DirectML; int m_myIndex; //--- OpenCL device buffers are float32 (see AI\Network.cl's fp32 conversion) while this class's //--- public CArrayDouble interface - and the DirectML backend's DLL boundary (DML_BufferRead/ //--- DML_BufferWrite, hardcoded to double[]) - stay double. This scratch array is the narrow/widen //--- point: populated from m_data before an OpenCL write, copied back into m_data after an OpenCL //--- read. Never touched on the DirectML or CPU-fallback paths. float m_data_f[]; public: CBufferDouble(void); ~CBufferDouble(void); //--- virtual bool BufferInit(uint count, double value); virtual bool BufferCreate(COpenCLMy *opencl); virtual bool BufferCreate(CDirectMLMy *directml); virtual bool BufferFree(void); virtual bool BufferRead(void); virtual bool BufferWrite(void); virtual int GetData(double &values[]); virtual int GetData(CArrayDouble *values); virtual int GetIndex(void) { return m_myIndex; } //--- virtual int Type(void) const { return defBufferDouble; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CBufferDouble::CBufferDouble(void) : m_myIndex(-1) { OpenCL = NULL; DirectML = NULL; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CBufferDouble::~CBufferDouble(void) { BufferFree(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferCreate(COpenCLMy *opencl) { BufferFree(); //--- if(CheckPointer(opencl) == POINTER_INVALID) return false; if(ArrayResize(m_data_f, m_data_total) < 0) return false; for(int i = 0; i < m_data_total; i++) m_data_f[i] = (float)m_data[i]; if((m_myIndex = opencl.AddBufferFromArray(m_data_f, 0, m_data_total, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR)) < 0) return false; OpenCL = opencl; //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferCreate(CDirectMLMy *directml) { BufferFree(); //--- if(CheckPointer(directml) == POINTER_INVALID) return false; if((m_myIndex = directml.BufferCreate(m_data_total)) < 0) return false; DirectML = directml; return DirectML.BufferWrite(m_myIndex, m_data, m_data_total); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferFree(void) { if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0) { if(!OpenCL.BufferFree(m_myIndex)) return false; m_myIndex = -1; OpenCL = NULL; return true; } if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0) { DirectML.BufferFree(m_myIndex); m_myIndex = -1; DirectML = NULL; return true; } //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferRead(void) { if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0) { if(ArrayResize(m_data_f, m_data_total) < 0) return false; if(!OpenCL.BufferRead(m_myIndex, m_data_f, 0, 0, m_data_total)) return false; for(int i = 0; i < m_data_total; i++) m_data[i] = (double)m_data_f[i]; return true; } if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0) return DirectML.BufferRead(m_myIndex, m_data, m_data_total); //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferWrite(void) { if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0) { if(ArrayResize(m_data_f, m_data_total) < 0) return false; for(int i = 0; i < m_data_total; i++) m_data_f[i] = (float)m_data[i]; return OpenCL.BufferWrite(m_myIndex, m_data_f, 0, 0, m_data_total); } if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0) return DirectML.BufferWrite(m_myIndex, m_data, m_data_total); //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CBufferDouble::BufferInit(uint count, double value) { if(!Reserve(count)) return false; m_data_total = (int)fmin(ArrayInitialize(m_data, value), count); //--- return m_data_total == count; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CBufferDouble::GetData(double &values[]) { if(!BufferRead()) return false; return ArrayCopy(values, m_data, 0, 0, m_data_total); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CBufferDouble::GetData(CArrayDouble *values) { if(!BufferRead()) return -1; values.Clear(); if(!values.AddArray(GetPointer(this))) return -1; return m_data_total; }