/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkGPUImage_hxx #define itkGPUImage_hxx namespace itk { template GPUImage::GPUImage() { m_DataManager = GPUImageDataManager>::New(); m_DataManager->SetTimeStamp(this->GetTimeStamp()); } template GPUImage::~GPUImage() = default; template void GPUImage::Allocate(bool initialize) { // allocate CPU memory - calling Allocate() in superclass Superclass::Allocate(initialize); // allocate GPU memory this->ComputeOffsetTable(); unsigned long numPixel = this->GetOffsetTable()[VImageDimension]; m_DataManager->SetBufferSize(sizeof(TPixel) * numPixel); m_DataManager->SetImagePointer(this); m_DataManager->SetCPUBufferPointer(Superclass::GetBufferPointer()); m_DataManager->Allocate(); /* prevent unnecessary copy from CPU to GPU at the beginning */ m_DataManager->SetTimeStamp(this->GetTimeStamp()); } template void GPUImage::Initialize() { // CPU image initialize Superclass::Initialize(); // GPU image initialize m_DataManager->Initialize(); this->ComputeOffsetTable(); unsigned long numPixel = this->GetOffsetTable()[VImageDimension]; m_DataManager->SetBufferSize(sizeof(TPixel) * numPixel); m_DataManager->SetImagePointer(this); m_DataManager->SetCPUBufferPointer(Superclass::GetBufferPointer()); m_DataManager->Allocate(); /* prevent unnecessary copy from CPU to GPU at the beginning */ m_DataManager->SetTimeStamp(this->GetTimeStamp()); } template void GPUImage::FillBuffer(const TPixel & value) { m_DataManager->SetGPUBufferDirty(); Superclass::FillBuffer(value); } template void GPUImage::SetPixel(const IndexType & index, const TPixel & value) { m_DataManager->SetGPUBufferDirty(); Superclass::SetPixel(index, value); } template const TPixel & GPUImage::GetPixel(const IndexType & index) const { m_DataManager->UpdateCPUBuffer(); return Superclass::GetPixel(index); } template TPixel & GPUImage::GetPixel(const IndexType & index) { /* Original version - very conservative m_DataManager->SetGPUBufferDirty(); return Superclass::GetPixel( index ); */ m_DataManager->UpdateCPUBuffer(); return Superclass::GetPixel(index); } template TPixel & GPUImage::operator[](const IndexType & index) { /* Original version - very conservative m_DataManager->SetGPUBufferDirty(); return Superclass::operator[]( index ); */ m_DataManager->UpdateCPUBuffer(); return Superclass::operator[](index); } template const TPixel & GPUImage::operator[](const IndexType & index) const { m_DataManager->UpdateCPUBuffer(); return Superclass::operator[](index); } template void GPUImage::SetPixelContainer(PixelContainer * container) { Superclass::SetPixelContainer(container); m_DataManager->SetCPUBufferPointer(Superclass::GetBufferPointer()); m_DataManager->SetCPUDirtyFlag(false); m_DataManager->SetGPUDirtyFlag(true); } template void GPUImage::UpdateBuffers() { m_DataManager->UpdateCPUBuffer(); m_DataManager->UpdateGPUBuffer(); } template TPixel * GPUImage::GetBufferPointer() { /* Original version - very conservative * Always set GPU dirty (even though pixel values are not modified) m_DataManager->SetGPUBufferDirty(); return Superclass::GetBufferPointer(); */ /* less conservative version - if you modify pixel value using * this pointer then you must set the image as modified manually!!! */ m_DataManager->UpdateCPUBuffer(); return Superclass::GetBufferPointer(); } template const TPixel * GPUImage::GetBufferPointer() const { // const does not change buffer, but if CPU is dirty then make it up-to-date m_DataManager->UpdateCPUBuffer(); return Superclass::GetBufferPointer(); } template GPUDataManager * GPUImage::GetGPUDataManager() { return m_DataManager.GetPointer(); } template void GPUImage::Graft(const Self * data) { using GPUImageDataManagerType = GPUImageDataManager; auto * ptr = const_cast(data->GetDataManager()); // call the superclass' implementation Superclass::Graft(ptr->GetImagePointer()); // call GPU data graft function m_DataManager->SetImagePointer(this); m_DataManager->Graft(ptr); // Synchronize timestamp of GPUImage and GPUDataManager m_DataManager->SetTimeStamp(this->GetTimeStamp()); } template void GPUImage::Graft(const DataObject * data) { const Self * ptr = dynamic_cast(data); if (ptr) { this->Graft(ptr); } else { // pointer could not be cast back down itkExceptionMacro("itk::GPUImage::Graft() cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name()); } } } // namespace itk #endif