From 0ceaf192b5445af5ecf1e76b8e5684ec6f7229ba Mon Sep 17 00:00:00 2001 From: ronag Date: Thu, 28 Oct 2010 19:36:37 +0000 Subject: [PATCH] 2.0.0.2: - Bluefish refactoring - Opengl -> Bluefish dma transfer - GPU interlacing - Fixed composite gpu frame transition bug - Frameconsumer video sync clock is not optional - Optimized memcpy git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@183 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- casparcg.sln | 6 + common/common.vcxproj | 38 +- common/common.vcxproj.filters | 51 +- common/exception/exceptions.h | 6 +- common/hardware/cpuid.cpp | 125 ----- common/hardware/cpuid.h | 94 ---- common/image/clear.cpp | 92 ---- common/image/copy.cpp | 97 ---- common/image/copy_field.cpp | 77 --- common/image/copy_field.h | 37 -- common/image/image.cpp | 55 -- common/image/image.h | 44 -- common/utility/memory.cpp | 84 ++++ common/utility/memory.h | 8 + core/caspar.config | 8 +- core/config.h | 2 +- .../bluefish/BlueFishVideoConsumer.cpp | 472 ------------------ .../consumer/bluefish/BlueFishVideoConsumer.h | 90 ---- core/consumer/bluefish/BluefishException.h | 39 -- .../bluefish/BluefishPlaybackStrategy.cpp | 135 ----- core/consumer/bluefish/bluefish_consumer.cpp | 314 ++++++++++++ .../consumer/bluefish/bluefish_consumer.h | 30 +- .../consumer/bluefish/exception.h | 17 +- core/consumer/bluefish/fwd.h | 12 + core/consumer/bluefish/memory.h | 58 +++ core/consumer/bluefish/util.h | 96 ++++ .../decklink/DecklinkVideoConsumer.cpp | 13 +- core/consumer/frame_consumer.h | 5 +- ...al_frame_consumer.cpp => oal_consumer.cpp} | 18 +- .../oal_consumer.h} | 29 +- ...gl_frame_consumer.cpp => ogl_consumer.cpp} | 24 +- .../consumer/ogl/ogl_consumer.h | 35 +- core/core.vcxproj | 75 ++- core/core.vcxproj.filters | 131 ++--- core/frame/composite_gpu_frame.cpp | 11 +- core/frame/gpu_frame.cpp | 72 ++- core/frame/gpu_frame.h | 23 +- core/frame/gpu_frame_processor.cpp | 38 +- core/producer/ffmpeg/audio/audio_decoder.cpp | 6 +- core/producer/ffmpeg/ffmpeg_producer.cpp | 2 +- core/producer/ffmpeg/input.cpp | 2 +- .../ffmpeg/video/video_deinterlacer.cpp | 2 +- .../ffmpeg/video/video_transformer.cpp | 95 ---- core/producer/flash/flash_producer.cpp | 66 ++- core/producer/image/image_loader.cpp | 2 +- core/producer/image/image_producer.cpp | 4 +- core/producer/image/image_scroll_producer.cpp | 47 +- .../transition/transition_producer.cpp | 21 +- core/renderer/render_device.cpp | 51 +- core/server.cpp | 38 +- test/test.cpp | 237 +++++++++ test/test.vcxproj | 95 ++++ test/test.vcxproj.filters | 22 + test/timer.h | 28 ++ 54 files changed, 1427 insertions(+), 1852 deletions(-) delete mode 100644 common/hardware/cpuid.cpp delete mode 100644 common/hardware/cpuid.h delete mode 100644 common/image/clear.cpp delete mode 100644 common/image/copy.cpp delete mode 100644 common/image/copy_field.cpp delete mode 100644 common/image/copy_field.h delete mode 100644 common/image/image.cpp delete mode 100644 common/image/image.h create mode 100644 common/utility/memory.cpp create mode 100644 common/utility/memory.h delete mode 100644 core/consumer/bluefish/BlueFishVideoConsumer.cpp delete mode 100644 core/consumer/bluefish/BlueFishVideoConsumer.h delete mode 100644 core/consumer/bluefish/BluefishException.h delete mode 100644 core/consumer/bluefish/BluefishPlaybackStrategy.cpp create mode 100644 core/consumer/bluefish/bluefish_consumer.cpp rename common/image/clear.h => core/consumer/bluefish/bluefish_consumer.h (56%) rename common/utility/types.h => core/consumer/bluefish/exception.h (72%) create mode 100644 core/consumer/bluefish/fwd.h create mode 100644 core/consumer/bluefish/memory.h create mode 100644 core/consumer/bluefish/util.h rename core/consumer/oal/{oal_frame_consumer.cpp => oal_consumer.cpp} (79%) rename core/consumer/{bluefish/BluefishPlaybackStrategy.h => oal/oal_consumer.h} (64%) rename core/consumer/ogl/{ogl_frame_consumer.cpp => ogl_consumer.cpp} (85%) rename common/image/copy.h => core/consumer/ogl/ogl_consumer.h (56%) delete mode 100644 core/producer/ffmpeg/video/video_transformer.cpp create mode 100644 test/test.cpp create mode 100644 test/test.vcxproj create mode 100644 test/test.vcxproj.filters create mode 100644 test/timer.h diff --git a/casparcg.sln b/casparcg.sln index 554d62a11..b22b6f996 100644 --- a/casparcg.sln +++ b/casparcg.sln @@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "core\core.vcxproj", "{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{CE1CD805-3904-4E58-824E-09C027585991}" +EndProject Global GlobalSection(SubversionScc) = preSolution Svn-Managed = True @@ -23,6 +25,10 @@ Global {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|Win32.Build.0 = Debug|Win32 {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|Win32.ActiveCfg = Release|Win32 {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|Win32.Build.0 = Release|Win32 + {CE1CD805-3904-4E58-824E-09C027585991}.Debug|Win32.ActiveCfg = Debug|Win32 + {CE1CD805-3904-4E58-824E-09C027585991}.Debug|Win32.Build.0 = Debug|Win32 + {CE1CD805-3904-4E58-824E-09C027585991}.Release|Win32.ActiveCfg = Release|Win32 + {CE1CD805-3904-4E58-824E-09C027585991}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/common/common.vcxproj b/common/common.vcxproj index ac4fdb01c..04dea5617 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -80,6 +80,8 @@ AnySuitable Speed true + false + true Windows @@ -96,22 +98,16 @@ - - - - - - + - @@ -122,34 +118,10 @@ ../StdAfx.h ../StdAfx.h - - ../StdAfx.h - ../StdAfx.h - - - ../StdAfx.h - ../StdAfx.h - - - ../StdAfx.h - ../StdAfx.h - - - ../StdAfx.h - ../StdAfx.h - - - ../StdAfx.h - ../StdAfx.h - ../StdAfx.h ../StdAfx.h - - ../StdAfx.h - ../StdAfx.h - ../StdAfx.h ../StdAfx.h @@ -166,6 +138,10 @@ ../StdAfx.h ../StdAfx.h + + ../StdAfx.h + ../StdAfx.h + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 8f605d951..e4ab23a71 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -11,9 +11,6 @@ {35ca385e-c4db-4fe7-858b-0a0bb678675f} - - {77be36fb-d4c0-415c-a5be-2cbec333ecbc} - {f4b0d63f-3cb3-4ab4-a6b9-3f249204dd3f} @@ -23,9 +20,6 @@ {11860e2d-8adf-4573-956b-785e59aef2b0} - - {5115d125-61f1-4fdd-9924-0f1bdced5d27} - {0d94bbc2-e196-4618-a90b-19392a3a0a8e} @@ -37,39 +31,24 @@ Source\log - - Source\io - Source\io Source\io - - Source\image - - - Source\image - - - Source\image - - - Source\image - Source\exception Source\concurrency - - Source\hardware - Source\utility + + Source\utility + @@ -87,24 +66,9 @@ Source\io - - Source\io - Source\io - - Source\image - - - Source\image - - - Source\image - - - Source\image - Source\exception @@ -123,15 +87,9 @@ Source - - Source\hardware - Source\utility - - Source\utility - Source\utility @@ -141,5 +99,8 @@ Source\gl + + Source\utility + \ No newline at end of file diff --git a/common/exception/exceptions.h b/common/exception/exceptions.h index 18127c772..929f64908 100644 --- a/common/exception/exceptions.h +++ b/common/exception/exceptions.h @@ -15,7 +15,11 @@ typedef boost::error_info msg_info; typedef boost::error_info inner_info; typedef boost::error_info line_info; -struct caspar_exception : virtual boost::exception, virtual std::exception {}; +struct caspar_exception : virtual boost::exception, virtual std::exception +{ + caspar_exception(){} + explicit caspar_exception(const char* msg) : std::exception(msg) {} +}; struct io_error : virtual caspar_exception {}; struct directory_not_found : virtual io_error {}; diff --git a/common/hardware/cpuid.cpp b/common/hardware/cpuid.cpp deleted file mode 100644 index 1b6eec0f3..000000000 --- a/common/hardware/cpuid.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../stdafx.h" - -#include "cpuid.h" - -#include - -#include - -namespace caspar { namespace common { - -cpuid::cpuid() : - FPU(0), VME(0), DE(0), PSE(0), TSC(0), MSR(0), PAE(0), MCE(0), CX8(0), APIC(0), SEP(0), MTRR(0), - PGE(0), MCA(0), CMOV(0), PAT(0), PSE_36(0), PSN(0), CLFSH(0), DS(0), ACPI(0), MMX(0), FXSR(0), - SSE(0), SSE2(0),SSE3(0),SSSE3(0), SSE4_1(0), SSE4_2(0), SSE5(0), SS(0), HTT(0), TM(0), - IA_64(0),Family(0), Model(0), ModelEx(0), Stepping(0), FamilyEx(0), Brand(0), Type(0) -{ - int CPUInfo[4] = {-1}; - __cpuid(CPUInfo, 0); - - int nIds = CPUInfo[0]; - std::string ID; - ID.append(reinterpret_cast(&CPUInfo[1]), 4); - ID.append(reinterpret_cast(&CPUInfo[3]), 4); - ID.append(reinterpret_cast(&CPUInfo[2]), 4); - - for (int i = 0; i <= nIds; ++i) - { - __cpuid(CPUInfo, i); - - if (i == 1) - { - Stepping = (CPUInfo[0] ) & 0x0F; - Model = (CPUInfo[0] >> 4 ) & 0x0F; - Family = (CPUInfo[0] >> 8 ) & 0x0F; - Type = (CPUInfo[0] >> 12) & 0x03; - ModelEx = (CPUInfo[0] >> 16) & 0x0F; - FamilyEx = (CPUInfo[0] >> 20) & 0xFF; - Brand = (CPUInfo[1] ) & 0xFF; - - if(ID == "GenuineIntel") - { - FPU = (CPUInfo[3] & (1 << 0)) != 0; - VME = (CPUInfo[3] & (1 << 1)) != 0; - DE = (CPUInfo[3] & (1 << 2)) != 0; - PSE = (CPUInfo[3] & (1 << 3)) != 0; - TSC = (CPUInfo[3] & (1 << 4)) != 0; - MSR = (CPUInfo[3] & (1 << 5)) != 0; - PAE = (CPUInfo[3] & (1 << 6)) != 0; - MCE = (CPUInfo[3] & (1 << 7)) != 0; - CX8 = (CPUInfo[3] & (1 << 8)) != 0; - APIC = (CPUInfo[3] & (1 << 9)) != 0; - // = (CPUInfo[3] & (1 << 10)) != 0; - SEP = (CPUInfo[3] & (1 << 11)) != 0; - MTRR = (CPUInfo[3] & (1 << 12)) != 0; - PGE = (CPUInfo[3] & (1 << 13)) != 0; - MCA = (CPUInfo[3] & (1 << 14)) != 0; - CMOV = (CPUInfo[3] & (1 << 15)) != 0; - PAT = (CPUInfo[3] & (1 << 16)) != 0; - PSE_36 = (CPUInfo[3] & (1 << 17)) != 0; - PSN = (CPUInfo[3] & (1 << 18)) != 0; - CLFSH = (CPUInfo[3] & (1 << 19)) != 0; - // = (CPUInfo[3] & (1 << 20)) != 0; - DS = (CPUInfo[3] & (1 << 21)) != 0; - ACPI = (CPUInfo[3] & (1 << 22)) != 0; - MMX = (CPUInfo[3] & (1 << 23)) != 0; - FXSR = (CPUInfo[3] & (1 << 24)) != 0; - SSE = (CPUInfo[3] & (1 << 25)) != 0; - SSE2 = (CPUInfo[3] & (1 << 26)) != 0; - SS = (CPUInfo[3] & (1 << 27)) != 0; - HTT = (CPUInfo[3] & (1 << 28)) != 0; - TM = (CPUInfo[3] & (1 << 29)) != 0; - // = (CPUInfo[3] & (1 << 30)) != 0; - IA_64 = (CPUInfo[3] & (1 << 31)) != 0; - - SSE3 = (CPUInfo[2] & (1 << 0)) != 0; - SSSE3 = (CPUInfo[2] & (1 << 9)) != 0; - SSE4_1 = (CPUInfo[2] & (1 << 19)) != 0; - SSE4_2 = (CPUInfo[2] & (1 << 20)) != 0; - } - else if(ID == "AuthenticAMD") - { - } - } - } - - if(SSE5) - SIMD = common::SSE5; - else if(SSE4_2) - SIMD = common::SSE4_2; - else if(SSE4_1) - SIMD = common::SSE4_1; - else if(SSSE3) - SIMD = common::SSSE3; - else if(SSE3) - SIMD = common::SSE3; - else if(SSE2) - SIMD = common::SSE2; - else if(SSE) - SIMD = common::SSE; - else - SIMD = common::REF; -} - -} -} diff --git a/common/hardware/cpuid.h b/common/hardware/cpuid.h deleted file mode 100644 index 3fe22d692..000000000 --- a/common/hardware/cpuid.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#pragma once - -namespace caspar { namespace common { - -enum SIMD -{ - AUTO, - REF, - SSE, - SSE2, - SSE3, - SSSE3, - SSE4_1, - SSE4_2, - SSE5 -}; - -struct cpuid -{ - cpuid(); - - bool FPU; //Floating Point Unit - bool VME; //Virtual Mode Extension - bool DE; //Debugging Extension - bool PSE; //Page Size Extension - bool TSC; //Time Stamp Counter - bool MSR; //Model Specific Registers - bool PAE; //Physical Address Extesnion - bool MCE; //Machine Check Extension - bool CX8; //CMPXCHG8 Instruction - bool APIC; //On-chip APIC Hardware - bool SEP; //SYSENTER SYSEXIT - bool MTRR; //Machine Type Range Registers - bool PGE; //Global Paging Extension - bool MCA; //Machine Check Architecture - bool CMOV; //Conditional Move Instrction - bool PAT; //Page Attribute Table - bool PSE_36; //36-bit Page Size Extension - bool PSN; //96-bit Processor Serial Number - bool CLFSH; //CLFLUSH Instruction - bool DS; //Debug Trace Store - bool ACPI; //ACPI Support - bool MMX; //MMX Technology - bool FXSR; //FXSAVE FXRSTOR (Fast save and restore) - bool SSE; //Streaming SIMD Extensions - bool SSE2; //Streaming SIMD Extensions 2 - bool SSE3; - bool SSSE3; - bool SSE4_1; - bool SSE4_2; - bool SSE5; - bool SS; //Self-Snoop - bool HTT; //Hyper-Threading Technology - bool TM; //Thermal Monitor Supported - bool IA_64; //IA-64 capable - - int Family; - int Model; - int ModelEx; - int Stepping; - int FamilyEx; - int Brand; - int Type; - - SIMD SIMD; - - //int CacheLineSize; - //int LogicalProcessorCount; - //int LocalAPICID; - -}; - -} -} \ No newline at end of file diff --git a/common/image/clear.cpp b/common/image/clear.cpp deleted file mode 100644 index d046e2cb3..000000000 --- a/common/image/clear.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../stdafx.h" - -#include "clear.h" - -#include -#include - -#include "../utility/types.h" - -#include "tbb/parallel_for.h" -#include "tbb/blocked_range.h" - -using namespace std::tr1::placeholders; - -namespace caspar{ -namespace common{ -namespace image{ - -static const size_t STRIDE = sizeof(__m128i)*4; - -void DoclearParallel(const tbb::blocked_range& r, const std::tr1::function& func, void* dest) -{ - size_t offset = r.begin()*STRIDE; - size_t size = r.size()*STRIDE; - func(reinterpret_cast(dest) + offset, size); -} - -void clearParallel(const std::tr1::function& func, void* dest, size_t size) -{ - tbb::parallel_for(tbb::blocked_range(0, size/STRIDE), std::bind(&DoclearParallel, std::placeholders::_1, func, dest)); -} - -clear_fun get_clear_fun(SIMD simd) -{ - if(simd >= SSE2) - return clearParallel_SSE2; - else - return clearParallel_REF; -} - -// TODO: (R.N) optimize => prefetch and cacheline loop unroll -void clear_SSE2(void* dest, size_t size) -{ - __m128i val = _mm_setzero_si128(); - __m128i* ptr = reinterpret_cast<__m128i*>(dest); - - int times = size / 16; - for(int i=0; i < times; ++i) - { - _mm_stream_si128(ptr, val); - ptr++; - } -} - -void clearParallel_SSE2(void* dest, size_t size) -{ - clearParallel(&clear_SSE2, dest, size); -} - -void clear_REF(void* dest, size_t size) -{ - __stosd(reinterpret_cast(dest), 0, size/4); -} - -void clearParallel_REF(void* dest, size_t size) -{ - clearParallel(&clear_REF, dest, size); -} - -} -} -} \ No newline at end of file diff --git a/common/image/copy.cpp b/common/image/copy.cpp deleted file mode 100644 index 7214ad9d7..000000000 --- a/common/image/copy.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../stdafx.h" - -#include "copy.h" - -#include -#include - -#include "../utility/types.h" - -#include "tbb/parallel_for.h" -#include "tbb/blocked_range.h" - -using namespace std::tr1::placeholders; - -namespace caspar{ -namespace common{ -namespace image{ - -static const size_t STRIDE = sizeof(__m128i)*4; - -void DocopyParallel(const tbb::blocked_range& r, const std::tr1::function& func, void* dest, const void* source) -{ - size_t offset = r.begin()*STRIDE; - size_t size = r.size()*STRIDE; - func(reinterpret_cast(dest) + offset, reinterpret_cast(source) + offset, size); -} - -void copyParallel(const std::tr1::function& func, void* dest, const void* source, size_t size) -{ - tbb::parallel_for(tbb::blocked_range(0, size/STRIDE), std::bind(&DocopyParallel, std::placeholders::_1, func, dest, source)); -} - -copy_fun get_copy_fun(SIMD simd) -{ - if(simd >= SSE2) - return copyParallel_SSE2; - else - return copyParallel_REF; -} - -// TODO: (R.N) optimize => prefetch and cacheline loop unroll -void copy_SSE2(void* dest, const void* source, size_t size) -{ - __m128i val = _mm_setzero_si128(); - __m128i* pD = reinterpret_cast<__m128i*>(dest); - const __m128i* pS = reinterpret_cast(source); - - int times = size / 16; - for(int i=0; i < times; ++i) - { - val = _mm_load_si128(pS); - _mm_stream_si128(pD, val); - - ++pD; - ++pS; - } - _mm_mfence(); //ensure last WC buffers get flushed to memory -} - -void copyParallel_SSE2(void* dest, const void* source, size_t size) -{ - copyParallel(©_SSE2, dest, source, size); -} - -void copy_REF(void* dest, const void* source, size_t size) -{ - __movsd(reinterpret_cast(dest), reinterpret_cast(source), size/4); -} - -void copyParallel_REF(void* dest, const void* source, size_t size) -{ - copyParallel(©_REF, dest, source, size); -} - -} -} -} \ No newline at end of file diff --git a/common/image/copy_field.cpp b/common/image/copy_field.cpp deleted file mode 100644 index 785fbffa2..000000000 --- a/common/image/copy_field.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../stdafx.h" - -#include "copy_field.h" -#include "copy.h" - -#include -#include - -#include "../utility/types.h" - -#include "tbb/parallel_for.h" -#include "tbb/blocked_range.h" - -using namespace std::tr1::placeholders; - -namespace caspar{ namespace common{ namespace image{ - -void Docopy_fieldParallel(size_t index, const std::tr1::function& func, void* dest, const void* source, size_t width4) -{ - size_t offset = index*width4; - size_t size = width4; - func(reinterpret_cast(dest) + offset, reinterpret_cast(source) + offset, size); -} - -void copy_fieldParallel(const std::tr1::function& func, void* dest, const void* source, size_t fieldIndex, size_t width, size_t height) -{ - tbb::parallel_for(fieldIndex, height, static_cast(2), std::bind(&Docopy_fieldParallel, std::placeholders::_1, func, dest, source, width*4)); // copy for each row -} - -copy_field_fun get_copy_field_fun(SIMD /*simd*/) -{ - //if(simd >= SSE2) - // return copy_fieldParallel_SSE2; - //else - return copy_fieldParallel_REF; // REF is faster -} - -void copy_fieldParallel_SSE2(unsigned char* dest, const unsigned char* source, size_t fieldIndex, size_t width, size_t height) -{ - copy_fieldParallel(©_SSE2, dest, source, fieldIndex, width, height); -} - -void copy_field_REF(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height) -{ - for(size_t rowIndex=fieldIndex; rowIndex < height; rowIndex+=2) - { - int offset = width*4*rowIndex; - __movsd(reinterpret_cast(&(pDest[offset])), reinterpret_cast(&(pSrc[offset])), width); - } -} - -void copy_fieldParallel_REF(unsigned char* dest, const unsigned char* source, size_t fieldIndex, size_t width, size_t height) -{ - copy_fieldParallel(©_REF, dest, source, fieldIndex, width, height); -} - -}}} \ No newline at end of file diff --git a/common/image/copy_field.h b/common/image/copy_field.h deleted file mode 100644 index 638455281..000000000 --- a/common/image/copy_field.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ -#pragma once - -#include "../hardware/cpuid.h" - -namespace caspar{ namespace common{ namespace image{ - -void copy_field_SSE2 (unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); -void copy_field_REF (unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); - -void copy_fieldParallel_SSE2 (unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); -void copy_fieldParallel_REF (unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); - -typedef void(*copy_field_fun)(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); -copy_field_fun get_copy_field_fun(SIMD simd = REF); - -}}} - - diff --git a/common/image/image.cpp b/common/image/image.cpp deleted file mode 100644 index 4bcdb01ae..000000000 --- a/common/image/image.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../stdafx.h" - -#include "image.h" - -#include "copy.h" -#include "copy_field.h" -#include "clear.h" -//#include "Transition.hpp" - -namespace caspar{ namespace common{ namespace image{ - -namespace detail -{ - cpuid my_cpuid; - copy_fun copy = get_copy_fun(my_cpuid.SIMD); - copy_field_fun copy_field = get_copy_field_fun(my_cpuid.SIMD); - clear_fun clear = get_clear_fun(my_cpuid.SIMD); -} - -void copy(void* dest, const void* source, size_t size) -{ - (*detail::copy)(dest, source, size); -} - -void copy_field(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height) -{ - (*detail::copy_field)(pDest, pSrc, fieldIndex, width, height); -} - -void clear(void* dest, size_t size) -{ - (*detail::clear)(dest, size); -} - -}}} \ No newline at end of file diff --git a/common/image/image.h b/common/image/image.h deleted file mode 100644 index d97a4edbb..000000000 --- a/common/image/image.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ -#pragma once - -#include "../utility/types.h" -#include "../hardware/cpuid.h" - -namespace caspar{ namespace common{ namespace image{ - -void set_version(SIMD simd = AUTO); - -void copy(void* dest, const void* source, size_t size); -void clear(void* dest, size_t size); -void copy_field(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); - -namespace detail -{ - typedef void(*copy_fun)(void*, const void*, size_t); - typedef void(*copy_field_fun)(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height); - typedef void(*clear_fun)(void*, size_t); - - extern copy_fun copy; - extern copy_field_fun copy_field; - extern clear_fun clear; -} - -}}} \ No newline at end of file diff --git a/common/utility/memory.cpp b/common/utility/memory.cpp new file mode 100644 index 000000000..c33dbeff1 --- /dev/null +++ b/common/utility/memory.cpp @@ -0,0 +1,84 @@ +#include "../stdafx.h" + +#include "memory.h" + +#include + +#include +#include + +namespace caspar { namespace common { + +void* memcpy_SSE2(void* dest, const void* source, size_t num) +{ + assert(dest != nullptr); + assert(source != nullptr); + assert(dest != source); + assert(num % 256 == 0); + __asm + { + mov esi, source; + mov edi, dest; + + mov ebx, num; + shr ebx, 7; + + cpy: + prefetchnta [esi+80h]; + + movdqa xmm0, [esi+00h]; + movdqa xmm1, [esi+10h]; + movdqa xmm2, [esi+20h]; + movdqa xmm3, [esi+30h]; + + movntdq [edi+00h], xmm0; + movntdq [edi+10h], xmm1; + movntdq [edi+20h], xmm2; + movntdq [edi+30h], xmm3; + + prefetchnta [esi+0C0h]; + + movdqa xmm4, [esi+40h]; + movdqa xmm5, [esi+50h]; + movdqa xmm6, [esi+60h]; + movdqa xmm7, [esi+70h]; + + movntdq [edi+40h], xmm4; + movntdq [edi+50h], xmm5; + movntdq [edi+60h], xmm6; + movntdq [edi+70h], xmm7; + + lea edi, [edi+80h]; + lea esi, [esi+80h]; + dec ebx; + + jnz cpy; + } + return dest; +} + +void* copy(void* dest, const void* source, size_t num) +{ + tbb::parallel_for(tbb::blocked_range(0, num/128), [&](const tbb::blocked_range& r) + { + memcpy_SSE2(reinterpret_cast(dest) + r.begin()*128, reinterpret_cast(source) + r.begin()*128, r.size()*128); + }, tbb::affinity_partitioner()); + + return dest; +} + +void* clear(void* dest, size_t size) +{ + tbb::parallel_for(tbb::blocked_range(0, size/16), [&](const tbb::blocked_range& r) + { + __m128i val = _mm_setzero_si128(); + __m128i* ptr = reinterpret_cast<__m128i*>(dest)+r.begin(); + __m128i* end = ptr + r.size(); + + while(ptr != end) + _mm_stream_si128(ptr++, val); + }); + return dest; +} + +}} \ No newline at end of file diff --git a/common/utility/memory.h b/common/utility/memory.h new file mode 100644 index 000000000..6c9b7671f --- /dev/null +++ b/common/utility/memory.h @@ -0,0 +1,8 @@ +#pragma once + +namespace caspar { namespace common { + +void* copy(void* dest, const void* source, size_t size); +void* clear(void* dest, size_t size); + +}} \ No newline at end of file diff --git a/core/caspar.config b/core/caspar.config index ebd79ce2f..7d68813ba 100644 --- a/core/caspar.config +++ b/core/caspar.config @@ -10,12 +10,16 @@ PAL - + + + 1 + true + diff --git a/core/config.h b/core/config.h index a9705eaaa..64d169472 100644 --- a/core/config.h +++ b/core/config.h @@ -20,4 +20,4 @@ #define TBB_USE_THREADING_TOOLS 1 -#define DISABLE_BLUEFISH +//#define DISABLE_BLUEFISH diff --git a/core/consumer/bluefish/BlueFishVideoConsumer.cpp b/core/consumer/bluefish/BlueFishVideoConsumer.cpp deleted file mode 100644 index 1c02aea1e..000000000 --- a/core/consumer/bluefish/BlueFishVideoConsumer.cpp +++ /dev/null @@ -1,472 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "..\..\StdAfx.h" - -#ifndef DISABLE_BLUEFISH - -#include -#include "BlueFishVideoConsumer.h" -#include "BluefishPlaybackStrategy.h" - -#include -#include - -#if defined(_MSC_VER) -#pragma warning (push, 1) // TODO: Legacy code, just disable warnings -#endif - -namespace caspar { -namespace bluefish { - -/////////////////////////////////////////// -// BlueFishVideoConsumer::EnumerateDevices -// RETURNS: Number of identified bluefish-cards -int BlueFishVideoConsumer::EnumerateDevices() -{ - CASPAR_LOG(info) << "Bleufhsi SDK version: " << BlueVelvetVersion; - BlueVelvetPtr pSDK(BlueVelvetFactory4()); - - if(pSDK != 0) { - int deviceCount = 0; - pSDK->device_enumerate(deviceCount); - return deviceCount; - } - else - return 0; -} - - -/////////////////////////////////////////// -// BlueFishVideoConsumer::Create -// PARAMS: deviceIndex(index of the card that is to be wrapped in a consumer) -// RETURNS: a new BlueFishVideoConsumer-object for the specified card -// COMMENT: Creates and initializes a consumer that outputs video to a bluefish-card -frame_consumer_ptr BlueFishVideoConsumer::Create(const frame_format_desc& format_desc, unsigned int deviceIndex) -{ - BlueFishFrameConsumerPtr card(new BlueFishVideoConsumer(format_desc)); - if(card != 0 && card->SetupDevice(deviceIndex) == false) - card.reset(); - - return card; -} - -//////////////////////////////////////// -// BlueFishVideoConsumer constructor -BlueFishVideoConsumer::BlueFishVideoConsumer(const frame_format_desc& format_desc) : format_desc_(format_desc), pSDK_(BlueVelvetFactory4()), currentFormat_(frame_format::pal), _deviceIndex(0), hasEmbeddedAudio_(false) -{ - frameBuffer_.set_capacity(1); - thread_ = boost::thread([=]{Run();}); -} - -//////////////////////////////////////// -// BlueFishVideoConsumer destructor -BlueFishVideoConsumer::~BlueFishVideoConsumer() -{ - frameBuffer_.push(nullptr), - thread_.join(); - ReleaseDevice(); -} - -/*******************/ -/** METHODS **/ -/*******************/ - -unsigned long BlueFishVideoConsumer::VidFmtFromFrameFormat(frame_format fmt) -{ - switch(fmt) - { - case frame_format::pal: return VID_FMT_PAL; - case frame_format::ntsc: return VID_FMT_NTSC; - case frame_format::x576p2500: return ULONG_MAX; //not supported - case frame_format::x720p5000: return VID_FMT_720P_5000; - case frame_format::x720p5994: return VID_FMT_720P_5994; - case frame_format::x720p6000: return VID_FMT_720P_6000; - case frame_format::x1080p2397: return VID_FMT_1080P_2397; - case frame_format::x1080p2400: return VID_FMT_1080P_2400; - case frame_format::x1080i5000: return VID_FMT_1080I_5000; - case frame_format::x1080i5994: return VID_FMT_1080I_5994; - case frame_format::x1080i6000: return VID_FMT_1080I_6000; - case frame_format::x1080p2500: return VID_FMT_1080P_2500; - case frame_format::x1080p2997: return VID_FMT_1080P_2997; - case frame_format::x1080p3000: return VID_FMT_1080P_3000; - default: return ULONG_MAX; - } -} - -TCHAR* GetBluefishCardDesc(int cardType) -{ - switch(cardType) - { - case CRD_BLUEDEEP_LT: return TEXT("Deepblue LT"); // D64 Lite - case CRD_BLUEDEEP_SD: return TEXT("Iridium SD"); // Iridium SD - case CRD_BLUEDEEP_AV: return TEXT("Iridium AV"); // Iridium AV - case CRD_BLUEDEEP_IO: return TEXT("Deepblue IO"); // D64 Full - case CRD_BLUEWILD_AV: return TEXT("Wildblue AV"); // D64 AV - case CRD_IRIDIUM_HD: return TEXT("Iridium HD"); // * Iridium HD - case CRD_BLUEWILD_RT: return TEXT("Wildblue RT"); // D64 RT - case CRD_BLUEWILD_HD: return TEXT("Wildblue HD"); // * BadAss G2 - case CRD_REDDEVIL: return TEXT("Iridium Full"); // Iridium Full - case CRD_BLUEDEEP_HD: // * BadAss G2 variant, proposed, reserved - case CRD_BLUEDEEP_HDS: return TEXT("Reserved for \"BasAss G2"); // * BadAss G2 variant, proposed, reserved - case CRD_BLUE_ENVY: return TEXT("Blue envy"); // Mini Din - case CRD_BLUE_PRIDE: return TEXT("Blue pride"); //Mini Din Output - case CRD_BLUE_GREED: return TEXT("Blue greed"); - case CRD_BLUE_INGEST: return TEXT("Blue ingest"); - case CRD_BLUE_SD_DUALLINK: return TEXT("Blue SD duallink"); - case CRD_BLUE_CATALYST: return TEXT("Blue catalyst"); - case CRD_BLUE_SD_DUALLINK_PRO: return TEXT("Blue SD duallink pro"); - case CRD_BLUE_SD_INGEST_PRO: return TEXT("Blue SD ingest pro"); - case CRD_BLUE_SD_DEEPBLUE_LITE_PRO: return TEXT("Blue SD deepblue lite pro"); - case CRD_BLUE_SD_SINGLELINK_PRO: return TEXT("Blue SD singlelink pro"); - case CRD_BLUE_SD_IRIDIUM_AV_PRO: return TEXT("Blue SD iridium AV pro"); - case CRD_BLUE_SD_FIDELITY: return TEXT("Blue SD fidelity"); - case CRD_BLUE_SD_FOCUS: return TEXT("Blue SD focus"); - case CRD_BLUE_SD_PRIME: return TEXT("Blue SD prime"); - case CRD_BLUE_EPOCH_2K_CORE: return TEXT("Blue epoch 2k core"); - case CRD_BLUE_EPOCH_2K_ULTRA: return TEXT("Blue epoch 2k ultra"); - case CRD_BLUE_EPOCH_HORIZON: return TEXT("Blue epoch horizon"); - case CRD_BLUE_EPOCH_CORE: return TEXT("Blue epoch core"); - case CRD_BLUE_EPOCH_ULTRA: return TEXT("Blue epoch ultra"); - case CRD_BLUE_CREATE_HD: return TEXT("Blue create HD"); - case CRD_BLUE_CREATE_2K: return TEXT("Blue create 2k"); - case CRD_BLUE_CREATE_2K_ULTRA: return TEXT("Blue create 2k ultra"); - default: return TEXT("Unknown"); - } -} - -bool BlueFishVideoConsumer::SetupDevice(unsigned int deviceIndex) -{ - return this->DoSetupDevice(deviceIndex); -} - -/* -// Original initialization code -bool BlueFishVideoConsumer::DoSetupDevice(unsigned int deviceIndex, std::wstring strDesiredFrameFormat) -{ - _deviceIndex = deviceIndex; - - unsigned long memFmt = MEM_FMT_ARGB_PC, updFmt = UPD_FMT_FRAME, vidFmt = VID_FMT_PAL, resFmt = RES_FMT_NORMAL; - unsigned long desiredVideoFormat = VID_FMT_PAL; - int iDummy; - - int bufferIndex=0; //Bufferindex used when initializing the buffers - - if(strDesiredFrameFormat.size() == 0) - strDesiredFrameFormat = TEXT("PAL"); - - frame_format casparVideoFormat = caspar::get_video_format(strDesiredFrameFormat); - desiredVideoFormat = BlueFishVideoConsumer::VidFmtFromFrameFormat(casparVideoFormat); - currentFormat_ = casparVideoFormat != FFormatInvalid ? casparVideoFormat : FFormatPAL; - if(desiredVideoFormat == ULONG_MAX) { - LOG << TEXT("BLUECARD ERROR: Unsupported videomode: ") << strDesiredFrameFormat << TEXT(". (device") << _deviceIndex << TEXT(")"); - return false; - } - - if(BLUE_FAIL(pSDK_->device_attach(_deviceIndex, FALSE))) { - LOG << TEXT("BLUECARD ERROR: Failed to attach device") << _deviceIndex; - return false; - } - - if(desiredVideoFormat != VID_FMT_PAL) { - int videoModeCount = pSDK_->count_video_mode(); - for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) { - EVideoMode videoMode = pSDK_->enum_video_mode(videoModeIndex); - if(videoMode == desiredVideoFormat) { - vidFmt = videoMode; - } - } - } - - if(vidFmt == VID_FMT_PAL) { - strDesiredFrameFormat = TEXT("PAL"); - currentFormat_ = FFormatPAL; - } - - if(BLUE_FAIL(pSDK_->set_video_framestore_style(vidFmt, memFmt, updFmt, resFmt))) { - LOG << TEXT("BLUECARD ERROR: Failed to set videomode to ") << strDesiredFrameFormat << TEXT(". (device ") << _deviceIndex << TEXT(")"); - return false; - } - - LOG << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << strDesiredFrameFormat << TEXT(". (device ") << _deviceIndex << TEXT(")"); - - if (pSDK_->has_output_key()) { - iDummy = TRUE; - int v4444 = FALSE, invert = FALSE, white = FALSE; - pSDK_->set_output_key(iDummy, v4444, invert, white); - } - - if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) { - pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI); - } - - - iDummy = FALSE; - pSDK_->set_vertical_flip(iDummy); - - // Get framestore parameters - if(BLUE_OK(pSDK_->render_buffer_sizeof(m_bufferCount, m_length, m_actual, m_golden))) { - LOG << TEXT("BLUECARD INFO: Buffers: ") << m_bufferCount << TEXT(", \"Length\": ") << m_length << TEXT(", Buffer size: ") << m_actual << TEXT(" (device ") << _deviceIndex << TEXT(")") << common::LogStream::Flush; - } - else { - LOG << TEXT("BLUECARD ERROR: Failed to get framestore parameters (device ") << _deviceIndex << TEXT(")"); - } - - pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, m_golden)); - - iDummy = TRUE; - pSDK_->set_output_video(iDummy); - - // Now specify video output buffer - pSDK_->render_buffer_update(0); - - pPlaybackControl_.reset(new FramePlaybackControl(FramePlaybackStrategyPtr(new BluefishPlaybackStrategy(this)))); - pPlaybackControl_->Start(); - - LOG << TEXT("BLUECARD INFO: Successfully initialized device ") << _deviceIndex; - return true; -} -*/ - -//New, improved(?) initialization code. -//Based on code sent from the bluefish-sdk support 2009-08-25. Email "RE: [sdk] Ang. RE: Issue with SD Lite Pro PCI-E" -bool BlueFishVideoConsumer::DoSetupDevice(unsigned int deviceIndex) -{ - _deviceIndex = deviceIndex; - - unsigned long memFmt = MEM_FMT_ARGB_PC, updFmt = UPD_FMT_FRAME, vidFmt = VID_FMT_PAL, resFmt = RES_FMT_NORMAL, engineMode = VIDEO_ENGINE_FRAMESTORE; - unsigned long desiredVideoFormat = VID_FMT_PAL; - int iDummy; - - int bufferIndex=0; //Bufferindex used when initializing the buffers - - if(BLUE_FAIL(pSDK_->device_attach(_deviceIndex, FALSE))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to attach device. (device " << _deviceIndex << TEXT(")"); - return false; - } - - int videoCardType = pSDK_->has_video_cardtype(); - CASPAR_LOG(info) << "BLUECARD INFO: Card type: " << GetBluefishCardDesc(videoCardType) << TEXT(". (device ") << _deviceIndex << TEXT(")"); - - desiredVideoFormat = BlueFishVideoConsumer::VidFmtFromFrameFormat(format_desc_.format); - currentFormat_ = format_desc_.format != frame_format::invalid ? format_desc_.format : frame_format::pal; - if(desiredVideoFormat == ULONG_MAX) { - CASPAR_LOG(error) << "BLUECARD ERROR: Unsupported videomode: " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")"); - return false; - } - - if(desiredVideoFormat != VID_FMT_PAL) { - int videoModeCount = pSDK_->count_video_mode(); - for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) { - EVideoMode videoMode = pSDK_->enum_video_mode(videoModeIndex); - if(videoMode == desiredVideoFormat) { - vidFmt = videoMode; - } - } - } - - if(vidFmt != desiredVideoFormat) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set desired videomode: " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")"); - } - - if(vidFmt == VID_FMT_PAL) { - currentFormat_ = frame_format::pal; - format_desc_ = frame_format_desc::format_descs[frame_format::pal]; - } - - DisableVideoOutput(); - - VARIANT value; - value.vt = VT_UI4; - - //Enable dual link output - value.ulVal = 1; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_DUAL_LINK_OUTPUT, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to enable dual link. (device " << _deviceIndex << TEXT(")"); - return false; - } - - value.ulVal = Signal_FormatType_4224; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set dual link format type to 4:2:2:4. (device " << _deviceIndex << TEXT(")"); - return false; - } - - //Setting output Video mode - value.ulVal = vidFmt; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_MODE, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set videomode. (device " << _deviceIndex << TEXT(")"); - return false; - } - - //Select Update Mode for output - value.ulVal = updFmt; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_UPDATE_TYPE, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set update type. (device " << _deviceIndex << TEXT(")"); - return false; - } - - //Select output memory format - value.ulVal = memFmt; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_MEMORY_FORMAT, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set memory format. (device " << _deviceIndex << TEXT(")"); - return false; - } - - //SELECT IMAGE ORIENTATION - value.ulVal = ImageOrientation_Normal; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_IMAGE_ORIENTATION, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set image orientation to normal. (device " << _deviceIndex << TEXT(")"); - } - - value.ulVal = CGR_RANGE; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_RGB_DATA_RANGE, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set RGB data range to CGR. (device " << _deviceIndex << TEXT(")"); - } - - value.ulVal = MATRIX_709_CGR; - if(vidFmt == VID_FMT_PAL) { - value.ulVal = MATRIX_601_CGR; - } - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_PREDEFINED_COLOR_MATRIX, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set colormatrix to " << (vidFmt == VID_FMT_PAL ? TEXT("601 CGR") : TEXT("709 CGR")) << TEXT(". (device ") << _deviceIndex << TEXT(")"); - } - - - //Disable embedded audio - value.ulVal = 1; - if(!BLUE_PASS(pSDK_->SetCardProperty(EMBEDDED_AUDIO_OUTPUT, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to enable embedded audio. (device " << _deviceIndex << TEXT(")"); - } - else { - CASPAR_LOG(info) << "BLUECARD INFO: Enabled embedded audio. (device " << _deviceIndex << TEXT(")"); - hasEmbeddedAudio_ = true; - } - - CASPAR_LOG(info) << "BLUECARD INFO: Successfully configured bluecard for " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")"); - - if (pSDK_->has_output_key()) { - iDummy = TRUE; - int v4444 = FALSE, invert = FALSE, white = FALSE; - pSDK_->set_output_key(iDummy, v4444, invert, white); - } - - if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) { - pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI); - } - - ULONG videoGolden = BlueVelvetGolden(vidFmt, memFmt, updFmt); - - pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, videoGolden)); - - pPlayback_ = std::make_shared(this); - - if(BLUE_FAIL(pSDK_->set_video_engine(engineMode))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set vido engine. (device " << _deviceIndex << TEXT(")"); - return false; - } - - EnableVideoOutput(); - - CASPAR_LOG(info) << "BLUECARD INFO: Successfully initialized device " << _deviceIndex; - return true; -} - -bool BlueFishVideoConsumer::ReleaseDevice() -{ - pPlayback_.reset(); - - pFrameManager_.reset(); - DisableVideoOutput(); - - if(pSDK_) { - pSDK_->device_detach(); - } - - CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << _deviceIndex; - return true; -} - -void BlueFishVideoConsumer::EnableVideoOutput() -{ - //Need sync. protection? - if(pSDK_) - { - VARIANT value; - value.vt = VT_UI4; - - //Deactivate channel - value.ulVal = 0; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_BLACKGENERATOR, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << _deviceIndex << TEXT(")"); - } - } -} - -void BlueFishVideoConsumer::DisableVideoOutput() -{ - //Need sync. protection? - if(pSDK_) - { - VARIANT value; - value.vt = VT_UI4; - - //Deactivate channel - value.ulVal = 1; - if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_BLACKGENERATOR, value))) { - CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << _deviceIndex << TEXT(")"); - } - } -} - -void BlueFishVideoConsumer::display(const gpu_frame_ptr& frame) -{ - if(frame == nullptr) - return; - - if(pException_ != nullptr) - std::rethrow_exception(pException_); - - frameBuffer_.push(frame); -} - -void BlueFishVideoConsumer::Run() -{ - while(true) - { - try - { - gpu_frame_ptr frame; - frameBuffer_.pop(frame); - if(frame == nullptr) - return; - - pPlayback_->display(frame); - } - catch(...) - { - pException_ = std::current_exception(); - } - } -} - -}} - -#endif \ No newline at end of file diff --git a/core/consumer/bluefish/BlueFishVideoConsumer.h b/core/consumer/bluefish/BlueFishVideoConsumer.h deleted file mode 100644 index 88d53f48c..000000000 --- a/core/consumer/bluefish/BlueFishVideoConsumer.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ -#pragma once - -#include "../../../common/concurrency/thread.h" -#include "BluefishException.h" -#include "BluefishFrameManager.h" -#include "../../consumer/frame_consumer.h" -#include "../../renderer/render_device.h" -#include -#include - -#define TIMEOUT 1000 - -class CBlueVelvet4; - -namespace caspar { - -namespace bluefish { - -typedef std::tr1::shared_ptr BlueVelvetPtr; - -class BlueFishVideoConsumer : public frame_consumer -{ - friend class BluefishPlaybackStrategy; - - BlueFishVideoConsumer(const frame_format_desc& format_desc); - BlueFishVideoConsumer(const BlueFishVideoConsumer&); - const BlueFishVideoConsumer& operator=(const BlueFishVideoConsumer&); - -public: - virtual ~BlueFishVideoConsumer(); - - static int EnumerateDevices(); - static frame_consumer_ptr Create(const frame_format_desc& format_desc, unsigned int deviceIndex); - - void display(const gpu_frame_ptr&); - - const frame_format_desc& get_frame_format_desc() const { return format_desc_; } - -private: - - void Run(); - - void EnableVideoOutput(); - void DisableVideoOutput(); - bool SetupDevice(unsigned int deviceIndex); - bool ReleaseDevice(); - - bool DoSetupDevice(unsigned int deviceIndex); - - BlueVelvetPtr pSDK_; - std::shared_ptr pPlayback_; - BluefishFrameManagerPtr pFrameManager_; - unsigned long m_bufferCount; - unsigned long m_length; - unsigned long m_actual; - unsigned long m_golden; - - unsigned long VidFmtFromFrameFormat(frame_format fmt); - - frame_format currentFormat_; - unsigned int _deviceIndex; - bool hasEmbeddedAudio_; - frame_format_desc format_desc_; - - std::exception_ptr pException_; - boost::thread thread_; - tbb::concurrent_bounded_queue frameBuffer_; -}; -typedef std::tr1::shared_ptr BlueFishFrameConsumerPtr; - -}} diff --git a/core/consumer/bluefish/BluefishException.h b/core/consumer/bluefish/BluefishException.h deleted file mode 100644 index 4ea18ebd9..000000000 --- a/core/consumer/bluefish/BluefishException.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#ifndef _CASPAR_BLUEFISHEXCEPTION_H__ -#define _CASPAR_BLUEFISHEXCEPTION_H__ - -#include - -namespace caspar { -namespace bluefish { - -class BluefishException : public std::exception -{ -public: - explicit BluefishException(const char* msg) : std::exception(msg) {} - ~BluefishException() {} -}; - -} //namespace bluefish -} //namespace caspar - -#endif //_CASPAR_BLUEFISHEXCEPTION_H__ \ No newline at end of file diff --git a/core/consumer/bluefish/BluefishPlaybackStrategy.cpp b/core/consumer/bluefish/BluefishPlaybackStrategy.cpp deleted file mode 100644 index 013b0ce93..000000000 --- a/core/consumer/bluefish/BluefishPlaybackStrategy.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ - -#include "../../StdAfx.h" - -#include "../../../common/image/image.h" -#include -#include - -#include - -#include "BluefishPlaybackStrategy.h" -#include "BluefishVideoConsumer.h" - -namespace caspar { namespace bluefish { - -using namespace caspar::common; - -struct BluefishPlaybackStrategy::Implementation -{ - Implementation(BlueFishVideoConsumer* pConsumer) : pConsumer_(pConsumer), currentReservedFrameIndex_(0) - { - auto frame = pConsumer->pFrameManager_->CreateFrame(); - if(frame != 0) - reservedFrames_.push_back(frame); - else { - throw std::exception("Failed to reserve temporary bluefishframe"); - } - frame.reset(); - - frame = pConsumer->pFrameManager_->CreateFrame(); - if(frame != 0) - reservedFrames_.push_back(frame); - else { - throw std::exception("Failed to reserve temporary bluefishframe"); - } - - memset(&hancStreamInfo_, 0, sizeof(hancStreamInfo_)); - } - std::shared_ptr GetReservedFrame() { - std::shared_ptr frame = reservedFrames_[currentReservedFrameIndex_]; - currentReservedFrameIndex_ ^= 1; - return frame; - } - - void DisplayFrame(const gpu_frame_ptr& frame) - { - if(frame != nullptr) { - if(pConsumer_->pFrameManager_.get() == reinterpret_cast(frame->tag())) { - DoRender(std::static_pointer_cast(frame)); - } - else { - std::shared_ptr pTempFrame = reservedFrames_[currentReservedFrameIndex_]; - if(frame->size() == pTempFrame->size()) { - common::image::copy(pTempFrame->data(), frame->data(), pTempFrame->size()); - DoRender(pTempFrame); - } - - currentReservedFrameIndex_ ^= 1; - } - } - else { - CASPAR_LOG(error) << "BLUEFISH: Tried to render frame with no data"; - } - } - - void DoRender(const std::shared_ptr& frame) { - static bool doLog = true; - static int frameID = 0; - // video synch - unsigned long fieldCount = 0; - pConsumer_->pSDK_->wait_output_video_synch(UPD_FMT_FRAME, fieldCount); - - // Host->PCI in_Frame buffer to the card buffer - pConsumer_->pSDK_->system_buffer_write_async(frame->data(), frame->size(), 0, frame->meta_data(), 0); - if(BLUE_FAIL(pConsumer_->pSDK_->render_buffer_update(frame->meta_data()))) { - /*pConsumer_->pSDK_->system_buffer_write_async(frame->data(), frame->size(), 0, frameID, 0); - if(BLUE_FAIL(pConsumer_->pSDK_->render_buffer_update(frameID))) {*/ - if(doLog) { - CASPAR_LOG(error) << "BLUEFISH: render_buffer_update failed"; - doLog = false; - } - } - else - doLog = true; - - frameID = (frameID+1) & 3; - } - - BlueFishVideoConsumer* pConsumer_; - std::vector> reservedFrames_; - int currentReservedFrameIndex_; - - hanc_stream_info_struct hancStreamInfo_; -}; - -BluefishPlaybackStrategy::BluefishPlaybackStrategy(BlueFishVideoConsumer* pConsumer) : pImpl_(new Implementation(pConsumer)) -{ } - -BluefishPlaybackStrategy::~BluefishPlaybackStrategy() -{ } -// -//FrameConsumer* BluefishPlaybackStrategy::GetConsumer() -//{ -// return pImpl_->pConsumer_; -//} -// -//gpu_frame_ptr BluefishPlaybackStrategy::GetReservedFrame() { -// return pImpl_->GetReservedFrame(); -//} - -void BluefishPlaybackStrategy::display(const gpu_frame_ptr& frame) -{ - return pImpl_->DisplayFrame(frame); -} - -} //namespace bluefish -} //namespace caspar \ No newline at end of file diff --git a/core/consumer/bluefish/bluefish_consumer.cpp b/core/consumer/bluefish/bluefish_consumer.cpp new file mode 100644 index 000000000..1cc3af832 --- /dev/null +++ b/core/consumer/bluefish/bluefish_consumer.cpp @@ -0,0 +1,314 @@ +/* +* copyright (c) 2010 Sveriges Television AB +* +* This file is part of CasparCG. +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +*/ + +#include "..\..\StdAfx.h" + +#ifndef DISABLE_BLUEFISH + +#include "fwd.h" +#include "bluefish_consumer.h" +#include "util.h" +#include "exception.h" +#include "memory.h" + +#include "../../frame/gpu_frame.h" + +#include + +#include + +#include +#include + +#if defined(_MSC_VER) +#pragma warning (push, 1) // TODO: Legacy code, just disable warnings +#endif + +namespace caspar { namespace bluefish { + +struct consumer::implementation +{ + implementation::implementation(const frame_format_desc& format_desc, unsigned int device_index, bool embeed_audio) + : device_index_(device_index), format_desc_(format_desc), sdk_(BlueVelvetFactory4()), current_id_(0), embeed_audio_(embeed_audio) + { + mem_fmt_ = MEM_FMT_ARGB_PC; + upd_fmt_ = UPD_FMT_FRAME; + vid_fmt_ = VID_FMT_PAL; + res_fmt_ = RES_FMT_NORMAL; + engine_mode_ = VIDEO_ENGINE_FRAMESTORE; + + if(BLUE_FAIL(sdk_->device_attach(device_index_, FALSE))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to attach device.")); + + int videoCardType = sdk_->has_video_cardtype(); + CASPAR_LOG(info) << TEXT("BLUECARD INFO: Card type: ") << get_card_desc(videoCardType) << TEXT(". (device ") << device_index_ << TEXT(")"); + + //void* pBlueDevice = blue_attach_to_device(1); + //EBlueConnectorPropertySetting video_routing[1]; + //auto channel = BLUE_VIDEO_OUTPUT_CHANNEL_A; + //video_routing[0].channel = channel; + //video_routing[0].propType = BLUE_CONNECTOR_PROP_SINGLE_LINK; + //video_routing[0].connector = channel == BLUE_VIDEO_OUTPUT_CHANNEL_A ? BLUE_CONNECTOR_SDI_OUTPUT_A : BLUE_CONNECTOR_SDI_OUTPUT_B; + //blue_set_connector_property(pBlueDevice, 1, video_routing); + //blue_detach_from_device(&pBlueDevice); + + vid_fmt_ = ULONG_MAX; + auto desiredVideoFormat = vid_fmt_from_frame_format(format_desc_.format); + int videoModeCount = sdk_->count_video_mode(); + for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) + { + EVideoMode videoMode = sdk_->enum_video_mode(videoModeIndex); + if(videoMode == desiredVideoFormat) + vid_fmt_ = videoMode; + } + if(vid_fmt_ == ULONG_MAX) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode.")); + + // Set default video output channel + //if(BLUE_FAIL(set_card_property(sdk_, DEFAULT_VIDEO_OUTPUT_CHANNEL, channel))) + // CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set default channel. (device ") << device_index_ << TEXT(")"); + + //Setting output Video mode + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MODE, vid_fmt_))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode.")); + + //Select Update Mode for output + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_UPDATE_TYPE, upd_fmt_))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set update type. ")); + + disable_video_output(); + + //Enable dual link output + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT, 1))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to enable dual link.")); + + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set dual link format type to 4:2:2:4. (device " + boost::lexical_cast(device_index_) + ")")); + + //Select output memory format + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MEMORY_FORMAT, mem_fmt_))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set memory format.")); + + //Select image orientation + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal))) + CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set image orientation to normal. (device ") << device_index_ << TEXT(")"); + + // Select data range + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) + CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set RGB data range to CGR. (device ") << device_index_ << TEXT(")"); + + if(BLUE_FAIL(set_card_property(sdk_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR))) + CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set colormatrix to ") << (vid_fmt_ == VID_FMT_PAL ? TEXT("601 CGR") : TEXT("709 CGR")) << TEXT(". (device ") << device_index_ << TEXT(")"); + + //if(BLUE_FAIL(set_card_property(sdk_, EMBEDDED_AUDIO_OUTPUT, 0))) + // CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to enable embedded audio. (device ") << device_index_ << TEXT(")"); + //else + //{ + // CASPAR_LOG(info) << TEXT("BLUECARD INFO: Enabled embedded audio. (device ") << device_index_ << TEXT(")"); + // hasEmbeddedAudio_ = true; + //} + + CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << format_desc_ << TEXT(". (device ") << device_index_ << TEXT(")"); + + if (sdk_->has_output_key()) + { + int dummy = TRUE; int v4444 = FALSE; int invert = FALSE; int white = FALSE; + sdk_->set_output_key(dummy, v4444, invert, white); + } + + if(sdk_->GetHDCardType(device_index_) != CRD_HD_INVALID) + sdk_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI); + + if(BLUE_FAIL(sdk_->set_video_engine(engine_mode_))) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set vido engine.")); + + enable_video_output(); + + + page_locked_buffer::reserve_working_size(MAX_HANC_BUFFER_SIZE * 3); + for(int n = 0; n < 3; ++n) + hanc_buffers_.push_back(std::make_shared(MAX_HANC_BUFFER_SIZE)); + + frame_buffer_.set_capacity(1); + thread_ = boost::thread([=]{run();}); + + CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully initialized device ") << device_index_; + } + + ~implementation() + { + frame_buffer_.push(nullptr), + thread_.join(); + + disable_video_output(); + + if(sdk_) + sdk_->device_detach(); + + CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << device_index_; + } + + void enable_video_output() + { + if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 0))) + CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); + } + + void disable_video_output() + { + if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 1))) + CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); + } + + void display(const gpu_frame_ptr& frame) + { + if(frame == nullptr) + return; + + if(exception_ != nullptr) + std::rethrow_exception(exception_); + + frame_buffer_.push(frame); + } + + void do_display(const gpu_frame_ptr& frame) + { + auto hanc = hanc_buffers_[current_id_]; + current_id_ = (current_id_+1) % hanc_buffers_.size(); + + static size_t audio_samples = 1920; + static size_t audio_nchannels = 2; + static std::vector silence(audio_samples*audio_nchannels*2, 0); + + auto& frame_audio_data = frame->audio_data().empty() ? silence : frame->audio_data(); + + unsigned long fieldCount = 0; + sdk_->wait_output_video_synch(UPD_FMT_FRAME, fieldCount); + + if(embeed_audio_) + { + encode_hanc(reinterpret_cast(hanc->data()), frame_audio_data.data(), audio_samples, audio_nchannels); + + sdk_->system_buffer_write_async(frame->data(), + frame->size(), + nullptr, + BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE)); + + sdk_->system_buffer_write_async(hanc->data(), + hanc->size(), + nullptr, + BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_HANC)); + + transferring_frame_ = frame; + + if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image_HANC(current_id_)))) + CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed"); + } + else + { + sdk_->system_buffer_write_async(frame->data(), + frame->size(), + nullptr, + BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE)); + + if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image(current_id_)))) + CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed"); + } + } + + + void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, size_t audio_samples, size_t audio_nchannels) + { + auto card_type = sdk_->has_video_cardtype(); + auto sample_type = (AUDIO_CHANNEL_16BIT | AUDIO_CHANNEL_LITTLEENDIAN); + + hanc_stream_info_struct hanc_stream_info; + memset(&hanc_stream_info, 0, sizeof(hanc_stream_info)); + + hanc_stream_info.AudioDBNArray[0] = -1; + hanc_stream_info.AudioDBNArray[1] = -1; + hanc_stream_info.AudioDBNArray[2] = -1; + hanc_stream_info.AudioDBNArray[3] = -1; + hanc_stream_info.hanc_data_ptr = hanc_data; + hanc_stream_info.video_mode = vid_fmt_; + + auto emb_audio_flag = (blue_emb_audio_enable | blue_emb_audio_group1_enable); + + if (!is_epoch_card(card_type)) + { + encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, + audio_samples, sample_type, emb_audio_flag); + } + else + { + encode_hanc_frame_ex(card_type, &hanc_stream_info, audio_data, audio_nchannels, + audio_samples, sample_type, emb_audio_flag); + } + } + + void run() + { + while(true) + { + try + { + gpu_frame_ptr frame; + frame_buffer_.pop(frame); + if(frame == nullptr) + return; + + do_display(frame); + } + catch(...) + { + exception_ = std::current_exception(); + } + } + } + + BlueVelvetPtr sdk_; + + unsigned int device_index_; + frame_format_desc format_desc_; + + std::exception_ptr exception_; + boost::thread thread_; + tbb::concurrent_bounded_queue frame_buffer_; + + unsigned long mem_fmt_; + unsigned long upd_fmt_; + unsigned long vid_fmt_; + unsigned long res_fmt_; + unsigned long engine_mode_; + + gpu_frame_ptr transferring_frame_; + + std::vector hanc_buffers_; + int current_id_; + bool embeed_audio_; +}; + +consumer::consumer(const frame_format_desc& format_desc, unsigned int device_index, bool embeed_audio) : impl_(new implementation(format_desc, device_index, embeed_audio)){} +void consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);} +const frame_format_desc& consumer::get_frame_format_desc() const { return impl_->format_desc_;} + +}} + +#endif \ No newline at end of file diff --git a/common/image/clear.h b/core/consumer/bluefish/bluefish_consumer.h similarity index 56% rename from common/image/clear.h rename to core/consumer/bluefish/bluefish_consumer.h index 49a4f6dd9..5ddbfd2b7 100644 --- a/common/image/clear.h +++ b/core/consumer/bluefish/bluefish_consumer.h @@ -19,18 +19,24 @@ */ #pragma once -#include "../hardware/cpuid.h" +#include "../../frame/frame_fwd.h" +#include "../../consumer/frame_consumer.h" -namespace caspar{ namespace common{ namespace image{ +namespace caspar { namespace bluefish { -void clear_SSE2 (void* dest, size_t size); -void clear_REF (void* dest, size_t size); -void clearParallel_SSE2 (void* dest, size_t size); -void clearParallel_REF (void* dest, size_t size); - -typedef void(*clear_fun)(void*, size_t); -clear_fun get_clear_fun(SIMD simd = REF); - -}}} - +class consumer : public frame_consumer +{ +public: + consumer(const frame_format_desc& format_desc, unsigned int deviceIndex, bool embedd_audio = false); + + void display(const gpu_frame_ptr&); + + const frame_format_desc& get_frame_format_desc() const; + virtual bool has_sync_clock() const {return false;} +private: + struct implementation; + std::shared_ptr impl_; +}; +typedef std::tr1::shared_ptr BlueFishFrameConsumerPtr; +}} diff --git a/common/utility/types.h b/core/consumer/bluefish/exception.h similarity index 72% rename from common/utility/types.h rename to core/consumer/bluefish/exception.h index da508bb5b..6b70ec27d 100644 --- a/common/utility/types.h +++ b/core/consumer/bluefish/exception.h @@ -19,11 +19,16 @@ */ #pragma once -typedef unsigned __int8 u8; -typedef __int8 s8; +#include "../../../common/exception/exceptions.h" -typedef unsigned __int16 u16; -typedef __int16 s16; +#include -typedef unsigned __int32 u32; -typedef __int32 s32; \ No newline at end of file +namespace caspar { namespace bluefish { + +struct bluefish_exception : public caspar_exception +{ + bluefish_exception(){} + explicit bluefish_exception(const char* msg) : std::exception(msg) {} +}; + +}} \ No newline at end of file diff --git a/core/consumer/bluefish/fwd.h b/core/consumer/bluefish/fwd.h new file mode 100644 index 000000000..2b39a78fa --- /dev/null +++ b/core/consumer/bluefish/fwd.h @@ -0,0 +1,12 @@ +#pragma once + +class CBlueVelvet4; + +namespace caspar { namespace bluefish { + +typedef std::tr1::shared_ptr BlueVelvetPtr; + +class consumer; +typedef std::shared_ptr consumer_ptr; + +}} \ No newline at end of file diff --git a/core/consumer/bluefish/memory.h b/core/consumer/bluefish/memory.h new file mode 100644 index 000000000..9b4f19855 --- /dev/null +++ b/core/consumer/bluefish/memory.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include +#include "../../frame/frame_format.h" +#include "exception.h" + +namespace caspar { namespace bluefish { + +static const size_t MAX_HANC_BUFFER_SIZE = 256*1024; +static const size_t MAX_VBI_BUFFER_SIZE = 36*1920*4; + +struct page_locked_buffer +{ +public: + page_locked_buffer(size_t size) : size_(size), data_(static_cast(::VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))) + { + if(!data_) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed to allocate memory for paged locked buffer.")); + if(::VirtualLock(data_.get(), size_) == 0) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed to lock memory for paged locked buffer.")); + } + + static void reserve_working_size(size_t size) + { + SIZE_T workingSetMinSize = 0, workingSetMaxSize = 0; + if(::GetProcessWorkingSetSize(::GetCurrentProcess(), &workingSetMinSize, &workingSetMaxSize)) + { + CASPAR_LOG(debug) << TEXT("WorkingSet size: min = ") << workingSetMinSize << TEXT(", max = ") << workingSetMaxSize; + + workingSetMinSize += size; + workingSetMaxSize += size; + + if(!::SetProcessWorkingSetSize(::GetCurrentProcess(), workingSetMinSize, workingSetMaxSize)) + BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed set workingset.")); + } + } + + PBYTE data() const { return data_.get(); } + size_t size() const { return size_; } +private: + + struct virtual_free + { + void operator()(LPVOID lpAddress) + { + if(lpAddress != nullptr) + try{::VirtualFree(lpAddress, 0, MEM_RELEASE);}catch(...){} + } + }; + + size_t size_; + std::unique_ptr data_; +}; +typedef std::shared_ptr page_locked_buffer_ptr; + +}} \ No newline at end of file diff --git a/core/consumer/bluefish/util.h b/core/consumer/bluefish/util.h new file mode 100644 index 000000000..02f5b540a --- /dev/null +++ b/core/consumer/bluefish/util.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include "../../frame/frame_format.h" + +#include + +namespace caspar { namespace bluefish { + +inline bool is_epoch_card(int card_type) +{ + return card_type == CRD_BLUE_EPOCH_2K || + card_type == CRD_BLUE_EPOCH_HORIZON || + card_type == CRD_BLUE_EPOCH_2K_CORE || + card_type == CRD_BLUE_EPOCH_2K_ULTRA || + card_type == CRD_BLUE_EPOCH_CORE || + card_type == CRD_BLUE_EPOCH_ULTRA; +} + +inline unsigned long vid_fmt_from_frame_format(const frame_format& fmt) +{ + switch(fmt) + { + case frame_format::pal: return VID_FMT_PAL; + case frame_format::ntsc: return VID_FMT_NTSC; + case frame_format::x576p2500: return ULONG_MAX; //not supported + case frame_format::x720p5000: return VID_FMT_720P_5000; + case frame_format::x720p5994: return VID_FMT_720P_5994; + case frame_format::x720p6000: return VID_FMT_720P_6000; + case frame_format::x1080p2397: return VID_FMT_1080P_2397; + case frame_format::x1080p2400: return VID_FMT_1080P_2400; + case frame_format::x1080i5000: return VID_FMT_1080I_5000; + case frame_format::x1080i5994: return VID_FMT_1080I_5994; + case frame_format::x1080i6000: return VID_FMT_1080I_6000; + case frame_format::x1080p2500: return VID_FMT_1080P_2500; + case frame_format::x1080p2997: return VID_FMT_1080P_2997; + case frame_format::x1080p3000: return VID_FMT_1080P_3000; + default: return ULONG_MAX; + } +} + +inline wchar_t* get_card_desc(int cardType) +{ + switch(cardType) + { + case CRD_BLUEDEEP_LT: return L"Deepblue LT";// D64 Lite + case CRD_BLUEDEEP_SD: return L"Iridium SD";// Iridium SD + case CRD_BLUEDEEP_AV: return L"Iridium AV";// Iridium AV + case CRD_BLUEDEEP_IO: return L"Deepblue IO";// D64 Full + case CRD_BLUEWILD_AV: return L"Wildblue AV";// D64 AV + case CRD_IRIDIUM_HD: return L"Iridium HD";// * Iridium HD + case CRD_BLUEWILD_RT: return L"Wildblue RT";// D64 RT + case CRD_BLUEWILD_HD: return L"Wildblue HD";// * BadAss G2 + case CRD_REDDEVIL: return L"Iridium Full";// Iridium Full + case CRD_BLUEDEEP_HD: + case CRD_BLUEDEEP_HDS: return L"Reserved for \"BasAss G2";// * BadAss G2 variant, proposed, reserved + case CRD_BLUE_ENVY: return L"Blue envy"; // Mini Din + case CRD_BLUE_PRIDE: return L"Blue pride";//Mini Din Output + case CRD_BLUE_GREED: return L"Blue greed"; + case CRD_BLUE_INGEST: return L"Blue ingest"; + case CRD_BLUE_SD_DUALLINK: return L"Blue SD duallink"; + case CRD_BLUE_CATALYST: return L"Blue catalyst"; + case CRD_BLUE_SD_DUALLINK_PRO: return L"Blue SD duallink pro"; + case CRD_BLUE_SD_INGEST_PRO: return L"Blue SD ingest pro"; + case CRD_BLUE_SD_DEEPBLUE_LITE_PRO: return L"Blue SD deepblue lite pro"; + case CRD_BLUE_SD_SINGLELINK_PRO: return L"Blue SD singlelink pro"; + case CRD_BLUE_SD_IRIDIUM_AV_PRO: return L"Blue SD iridium AV pro"; + case CRD_BLUE_SD_FIDELITY: return L"Blue SD fidelity"; + case CRD_BLUE_SD_FOCUS: return L"Blue SD focus"; + case CRD_BLUE_SD_PRIME: return L"Blue SD prime"; + case CRD_BLUE_EPOCH_2K_CORE: return L"Blue epoch 2k core"; + case CRD_BLUE_EPOCH_2K_ULTRA: return L"Blue epoch 2k ultra"; + case CRD_BLUE_EPOCH_HORIZON: return L"Blue epoch horizon"; + case CRD_BLUE_EPOCH_CORE: return L"Blue epoch core"; + case CRD_BLUE_EPOCH_ULTRA: return L"Blue epoch ultra"; + case CRD_BLUE_CREATE_HD: return L"Blue create HD"; + case CRD_BLUE_CREATE_2K: return L"Blue create 2k"; + case CRD_BLUE_CREATE_2K_ULTRA: return L"Blue create 2k ultra"; + default: return L"Unknown"; + } +} + +inline int set_card_property(CBlueVelvet4 * pSdk, ULONG prop, ULONG value) +{ + VARIANT variantValue; + variantValue.vt = VT_UI4; + variantValue.ulVal = value; + return (pSdk->SetCardProperty(prop,variantValue)); +} + +inline int set_card_property(const std::shared_ptr pSdk, ULONG prop, ULONG value) +{ + return set_card_property(pSdk.get(), prop, value); +} + +}} \ No newline at end of file diff --git a/core/consumer/decklink/DecklinkVideoConsumer.cpp b/core/consumer/decklink/DecklinkVideoConsumer.cpp index dea018a1b..a71e3a392 100644 --- a/core/consumer/decklink/DecklinkVideoConsumer.cpp +++ b/core/consumer/decklink/DecklinkVideoConsumer.cpp @@ -29,7 +29,7 @@ #include "DeckLinkAPI_h.h" #include "../../frame/frame_format.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include "../../renderer/render_device.h" @@ -129,7 +129,7 @@ struct DecklinkVideoConsumer::Implementation : public IDeckLinkVideoOutputCallba std::shared_ptr pTempFrame = GetReservedFrame(); if(pTempFrame && frame->size() == pTempFrame->size()) { - common::image::copy(pTempFrame->data(), frame->data(), pTempFrame->size()); + common::copy(pTempFrame->data(), frame->data(), pTempFrame->size()); DoRender(pTempFrame); } else @@ -255,8 +255,6 @@ struct DecklinkVideoConsumer::Implementation : public IDeckLinkVideoOutputCallba void Run() { - auto period = boost::posix_time::microseconds(get_frame_format_period(format_desc_)*1000000); - auto time = boost::posix_time::microsec_clock::local_time(); while(true) { try @@ -265,12 +263,7 @@ struct DecklinkVideoConsumer::Implementation : public IDeckLinkVideoOutputCallba frameBuffer_.pop(frame); if(frame == nullptr) return; - - auto remaining = period - (boost::posix_time::microsec_clock::local_time() - time); - if(remaining > boost::posix_time::microseconds(5000)) - boost::this_thread::sleep(remaining - boost::posix_time::microseconds(5000)); - time = boost::posix_time::microsec_clock::local_time(); - + pPlayback_->DisplayFrame(frame); } catch(...) diff --git a/core/consumer/frame_consumer.h b/core/consumer/frame_consumer.h index 27dae150f..bbc661f4b 100644 --- a/core/consumer/frame_consumer.h +++ b/core/consumer/frame_consumer.h @@ -33,8 +33,9 @@ public: virtual ~frame_consumer() {} virtual const frame_format_desc& get_frame_format_desc() const = 0; - virtual void prepare(const gpu_frame_ptr&){}; - virtual void display(const gpu_frame_ptr&){}; + virtual void prepare(const gpu_frame_ptr&){} + virtual void display(const gpu_frame_ptr&){} + virtual bool has_sync_clock() const {return false;} }; typedef std::shared_ptr frame_consumer_ptr; typedef std::shared_ptr frame_consumer_const_ptr; diff --git a/core/consumer/oal/oal_frame_consumer.cpp b/core/consumer/oal/oal_consumer.cpp similarity index 79% rename from core/consumer/oal/oal_frame_consumer.cpp rename to core/consumer/oal/oal_consumer.cpp index 9e1322a5b..e94a5001f 100644 --- a/core/consumer/oal/oal_frame_consumer.cpp +++ b/core/consumer/oal/oal_consumer.cpp @@ -20,7 +20,7 @@ #include "../../StdAfx.h" -#include "oal_frame_consumer.h" +#include "oal_consumer.h" #include "../../frame/gpu_frame.h" #include "../../frame/frame_format.h" @@ -76,11 +76,11 @@ private: bool OnGetData(sf::SoundStream::Chunk& data) { gpu_frame_ptr frame; - //if(!external_chunks_.try_pop(frame)) - //{ - //CASPAR_LOG(trace) << "Sound Buffer Underrun"; + if(!external_chunks_.try_pop(frame)) + { + CASPAR_LOG(trace) << "Sound Buffer Underrun"; external_chunks_.pop(frame); - //} + } if(frame == nullptr) { @@ -101,7 +101,7 @@ private: }; typedef std::shared_ptr sound_channelPtr; -struct oal_frame_consumer::implementation : boost::noncopyable +struct consumer::implementation : boost::noncopyable { implementation(const frame_format_desc& format_desc) : format_desc_(format_desc) { @@ -117,7 +117,7 @@ struct oal_frame_consumer::implementation : boost::noncopyable caspar::frame_format_desc format_desc_; }; -oal_frame_consumer::oal_frame_consumer(const caspar::frame_format_desc& format_desc) : impl_(new implementation(format_desc)){} -const caspar::frame_format_desc& oal_frame_consumer::get_frame_format_desc() const{return impl_->format_desc_;} -void oal_frame_consumer::prepare(const gpu_frame_ptr& frame){impl_->push(frame);} +consumer::consumer(const caspar::frame_format_desc& format_desc) : impl_(new implementation(format_desc)){} +const caspar::frame_format_desc& consumer::get_frame_format_desc() const{return impl_->format_desc_;} +void consumer::prepare(const gpu_frame_ptr& frame){impl_->push(frame);} }} diff --git a/core/consumer/bluefish/BluefishPlaybackStrategy.h b/core/consumer/oal/oal_consumer.h similarity index 64% rename from core/consumer/bluefish/BluefishPlaybackStrategy.h rename to core/consumer/oal/oal_consumer.h index 781a11567..e3cf70c59 100644 --- a/core/consumer/bluefish/BluefishPlaybackStrategy.h +++ b/core/consumer/oal/oal_consumer.h @@ -17,28 +17,23 @@ * along with CasparCG. If not, see . * */ - #pragma once -#include "../../frame/gpu_frame.h" #include "../../consumer/frame_consumer.h" -namespace caspar { -namespace bluefish { +namespace caspar { namespace audio { -class BlueFishVideoConsumer; - -class BluefishPlaybackStrategy +class consumer : public frame_consumer { - struct Implementation; - std::shared_ptr pImpl_; - -public: - explicit BluefishPlaybackStrategy(BlueFishVideoConsumer* pConsumer); - virtual ~BluefishPlaybackStrategy(); - - void display(const gpu_frame_ptr&); +public: + explicit consumer(const frame_format_desc& format_desc); + + const frame_format_desc& get_frame_format_desc() const; + void prepare(const gpu_frame_ptr& frame); + virtual bool has_sync_clock() const {return true;} +private: + struct implementation; + std::shared_ptr impl_; }; -} //namespace bluefish -} //namespace caspar +}} \ No newline at end of file diff --git a/core/consumer/ogl/ogl_frame_consumer.cpp b/core/consumer/ogl/ogl_consumer.cpp similarity index 85% rename from core/consumer/ogl/ogl_frame_consumer.cpp rename to core/consumer/ogl/ogl_consumer.cpp index 4fc0fc2c1..d48bd43dc 100644 --- a/core/consumer/ogl/ogl_frame_consumer.cpp +++ b/core/consumer/ogl/ogl_consumer.cpp @@ -24,11 +24,11 @@ #pragma warning (disable : 4244) #endif -#include "ogl_frame_consumer.h" +#include "ogl_consumer.h" #include "../../frame/frame_format.h" #include "../../frame/gpu_frame.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include @@ -45,7 +45,7 @@ void GL_CHECK() BOOST_THROW_EXCEPTION(ogl_error() << msg_info(boost::lexical_cast(glGetError()))); } -struct ogl_frame_consumer::implementation : boost::noncopyable +struct consumer::implementation : boost::noncopyable { implementation(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : format_desc_(format_desc), stretch_(stretch), texture_(0), pbo_index_(0), screen_width_(0), screen_height_(0), windowed_(windowed) @@ -226,7 +226,7 @@ struct ogl_frame_consumer::implementation : boost::noncopyable if(ptr != NULL) { - common::image::copy(ptr, frame->data(), frame->size()); + common::copy(ptr, frame->data(), frame->size()); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); } @@ -248,10 +248,7 @@ struct ogl_frame_consumer::implementation : boost::noncopyable void run() { init(); - - auto period = boost::posix_time::microseconds(static_cast(get_frame_format_period(format_desc_)*1000000.0)); - auto time = boost::posix_time::microsec_clock::local_time(); - + gpu_frame_ptr frame; do { @@ -260,11 +257,6 @@ struct ogl_frame_consumer::implementation : boost::noncopyable frame_buffer_.pop(frame); if(frame != nullptr) { - auto remaining = period - (boost::posix_time::microsec_clock::local_time() - time); - if(remaining > boost::posix_time::microseconds(5000)) - boost::this_thread::sleep(remaining - boost::posix_time::microseconds(5000)); - time = boost::posix_time::microsec_clock::local_time(); - sf::Event e; while(window_->GetEvent(e)){} window_->SetActive(); @@ -302,8 +294,8 @@ struct ogl_frame_consumer::implementation : boost::noncopyable tbb::concurrent_bounded_queue frame_buffer_; }; -ogl_frame_consumer::ogl_frame_consumer(const caspar::frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) +consumer::consumer(const caspar::frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){} -const caspar::frame_format_desc& ogl_frame_consumer::get_frame_format_desc() const{return impl_->format_desc_;} -void ogl_frame_consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);} +const caspar::frame_format_desc& consumer::get_frame_format_desc() const{return impl_->format_desc_;} +void consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);} }} diff --git a/common/image/copy.h b/core/consumer/ogl/ogl_consumer.h similarity index 56% rename from common/image/copy.h rename to core/consumer/ogl/ogl_consumer.h index fb5c2a561..184309239 100644 --- a/common/image/copy.h +++ b/core/consumer/ogl/ogl_consumer.h @@ -19,19 +19,30 @@ */ #pragma once -#include "../hardware/cpuid.h" +#include "../../consumer/frame_consumer.h" -namespace caspar{ namespace common{ namespace image{ - -void copy_SSE2 (void* dest, const void* source, size_t size); -void copy_REF (void* dest, const void* source, size_t size); - -void copyParallel_SSE2 (void* dest, const void* source, size_t size); -void copyParallel_REF (void* dest, const void* source, size_t size); +namespace caspar { namespace ogl { -typedef void(*copy_fun)(void*, const void*, size_t); -copy_fun get_copy_fun(SIMD simd = REF); - -}}} +struct ogl_error : virtual caspar_exception{}; +enum stretch +{ + none, + uniform, + fill, + uniform_to_fill +}; +class consumer : public frame_consumer +{ +public: + explicit consumer(const frame_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false); + + const frame_format_desc& get_frame_format_desc() const; + void display(const gpu_frame_ptr& frame); +private: + struct implementation; + std::shared_ptr impl_; +}; + +}} \ No newline at end of file diff --git a/core/core.vcxproj b/core/core.vcxproj index bb369d011..eb211ff96 100644 --- a/core/core.vcxproj +++ b/core/core.vcxproj @@ -77,7 +77,7 @@ true - sfml-audio-d.lib;sfml-window-d.lib;OpenGL32.lib;FreeImage.lib;GLee.lib;Winmm.lib;Ws2_32.lib;BlueVelvet3_d.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;swscale-0.lib;%(AdditionalDependencies) + BlueHancUtils_d.lib;sfml-audio-d.lib;sfml-window-d.lib;OpenGL32.lib;FreeImage.lib;GLee.lib;Winmm.lib;Ws2_32.lib;BlueVelvet3_d.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;swscale-0.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) @@ -118,13 +118,15 @@ ProgramDatabase true NDEBUG;_VC80_UPGRADE=0x0710;%(PreprocessorDefinitions) + false + true - sfml-audio.lib;sfml-window.lib;OpenGL32.lib;FreeImage.lib;Winmm.lib;Ws2_32.lib;Bluevelvet3.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;SWSCALE-0.lib;tbb.lib;Glee.lib;%(AdditionalDependencies) + BlueHancUtils.lib;sfml-audio.lib;sfml-window.lib;OpenGL32.lib;FreeImage.lib;Winmm.lib;Ws2_32.lib;Bluevelvet3.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;SWSCALE-0.lib;tbb.lib;Glee.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) @@ -150,14 +152,16 @@ - - - + + + + + - - + + @@ -206,17 +210,9 @@ - + ../../StdAfx.h ../../StdAfx.h - true - true - - - ../../StdAfx.h - ../../StdAfx.h - true - true NotUsing @@ -226,11 +222,11 @@ ../../StdAfx.h ../../StdAfx.h - + ../../StdAfx.h ../../StdAfx.h - + ../../StdAfx.h ../../StdAfx.h @@ -255,8 +251,8 @@ ../../StdAfx.h - ../../../StdAfx.h - ../../../StdAfx.h + ../../../stdafx.h + ../../../stdafx.h ../../StdAfx.h @@ -267,40 +263,43 @@ ../../StdAfx.h - ../../../StdAfx.h - ../../../StdAfx.h + ../../../stdafx.h + ../../../stdafx.h - ../../../StdAfx.h - ../../../StdAfx.h + ../../../stdafx.h + ../../../stdafx.h - ../../../StdAfx.h - ../../../StdAfx.h + ../../../stdafx.h + ../../../stdafx.h - ../../StdAfx.h - "../../StdAfx.h + ../../stdAfx.h + ../../stdAfx.h - ../../StdAfx.h - ../../StdAfx.h + ../../stdAfx.h + ../../stdAfx.h - ../../StdAfx.h - ../../StdAfx.h + ../../stdAfx.h + ../../stdAfx.h - NotUsing + ../../stdAfx.h + + NotUsing + NotUsing - ../../StdAfx.h - ../../StdAfx.h + ../../stdAfx.h + ../../stdAfx.h - ../../StdAfx.h - ../../StdAfx.h + ../../stdAfx.h + ../../stdAfx.h ../../StdAfx.h @@ -382,8 +381,8 @@ true - true true + true diff --git a/core/core.vcxproj.filters b/core/core.vcxproj.filters index acf013515..0c4287ab2 100644 --- a/core/core.vcxproj.filters +++ b/core/core.vcxproj.filters @@ -126,27 +126,12 @@ Source - - Source\consumer\bluefish - - - Source\consumer\bluefish - - - Source\consumer\bluefish - Source\consumer\decklink Source\consumer\decklink\interop - - Source\consumer\oal - - - Source\consumer\ogl - Source\consumer @@ -171,24 +156,6 @@ Source\producer\ffmpeg\video - - Source\producer\flash - - - Source\producer\flash - - - Source\producer\flash - - - Source\producer\flash\interop - - - Source\producer\flash\interop - - - Source\producer\flash\interop - Source\producer\image @@ -219,11 +186,50 @@ Source\producer\ffmpeg\video + + Source\frame\gpu + Source\producer\flash - - Source\frame\gpu + + Source\producer\flash + + + Source\producer\flash + + + Source\producer\flash + + + Source\producer\flash\interop + + + Source\producer\flash\interop + + + Source\producer\flash\interop + + + Source\consumer\bluefish + + + Source\consumer\bluefish + + + Source\consumer\bluefish + + + Source\consumer\bluefish + + + Source\consumer\ogl + + + Source\consumer\oal + + + Source\consumer\bluefish @@ -266,24 +272,12 @@ Source - - Source\consumer\bluefish - - - Source\consumer\bluefish - Source\consumer\decklink Source\consumer\decklink\interop - - Source\consumer\oal - - - Source\consumer\ogl - Source\producer\color @@ -302,21 +296,6 @@ Source\producer\ffmpeg\video - - Source\producer\flash - - - Source\producer\flash - - - Source\producer\flash - - - Source\producer\flash\interop - - - Source\producer\flash\interop - Source\producer\image @@ -338,14 +317,38 @@ Source\frame\gpu + + Source\frame\gpu + Source\producer\ffmpeg\video Source\producer\flash - - Source\frame\gpu + + Source\producer\flash + + + Source\producer\flash + + + Source\producer\flash + + + Source\producer\flash\interop + + + Source\producer\flash\interop + + + Source\consumer\ogl + + + Source\consumer\oal + + + Source\consumer\bluefish diff --git a/core/frame/composite_gpu_frame.cpp b/core/frame/composite_gpu_frame.cpp index 36c90149e..19c815031 100644 --- a/core/frame/composite_gpu_frame.cpp +++ b/core/frame/composite_gpu_frame.cpp @@ -1,8 +1,8 @@ #include "../StdAfx.h" #include "composite_gpu_frame.h" -#include "../../common/image/copy.h" #include "../../common/gl/utility.h" +#include "../../common/utility/memory.h" #include #include @@ -44,7 +44,14 @@ struct composite_gpu_frame::implementation void add(const gpu_frame_ptr& frame) { frames_.push_back(frame); - mix_audio_safe(audio_data_, frame->audio_data()); + + if(audio_data_.empty()) + audio_data_ = std::move(frame->audio_data()); + else + { + for(size_t n = 0; n < frame->audio_data().size(); ++n) + audio_data_[n] = static_cast(static_cast(audio_data_[n]) + static_cast(frame->audio_data()[n]) & 0xFFFF); + } } unsigned char* data() diff --git a/core/frame/gpu_frame.cpp b/core/frame/gpu_frame.cpp index ddb085b75..53398350c 100644 --- a/core/frame/gpu_frame.cpp +++ b/core/frame/gpu_frame.cpp @@ -1,15 +1,71 @@ #include "../StdAfx.h" #include "gpu_frame.h" -#include "../../common/image/copy.h" +#include "../../common/utility/memory.h" #include "../../common/gl/utility.h" namespace caspar { +GLubyte progressive_pattern[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +GLubyte upper_pattern[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; + +GLubyte lower_pattern[] = { + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff}; + struct gpu_frame::implementation { implementation(size_t width, size_t height) - : pbo_(0), data_(nullptr), width_(width), height_(height), size_(width*height*4), reading_(false), texture_(0), alpha_(1.0f) + : pbo_(0), data_(nullptr), width_(width), height_(height), size_(width*height*4), + reading_(false), texture_(0), alpha_(1.0f), x_(0.0f), y_(0.0f), mode_(video_mode::progressive) { } @@ -103,6 +159,14 @@ struct gpu_frame::implementation glPushMatrix(); glTranslatef(x_*2.0f, y_*2.0f, 0.0f); glColor4f(1.0f, 1.0f, 1.0f, alpha_); + + if(mode_ == video_mode::progressive) + glPolygonStipple(progressive_pattern); + else if(mode_ == video_mode::upper) + glPolygonStipple(upper_pattern); + else if(mode_ == video_mode::lower) + glPolygonStipple(lower_pattern); + CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_)); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); @@ -126,6 +190,7 @@ struct gpu_frame::implementation alpha_ = 1.0f; x_ = 0.0f; y_ = 0.0f; + mode_ = video_mode::progressive; } gpu_frame* self_; @@ -141,6 +206,7 @@ struct gpu_frame::implementation float alpha_; float x_; float y_; + video_mode mode_; }; gpu_frame::gpu_frame(size_t width, size_t height) : impl_(new implementation(width, height)){} @@ -161,4 +227,6 @@ void gpu_frame::alpha(float value){ impl_->alpha_ = value;} float gpu_frame::x() const { return impl_->x_;} float gpu_frame::y() const { return impl_->y_;} void gpu_frame::translate(float x, float y) { impl_->x_ += x; impl_->y_ += y; } +void gpu_frame::mode(video_mode mode){ impl_->mode_ = mode;} +video_mode gpu_frame::mode() const{ return impl_->mode_;} } \ No newline at end of file diff --git a/core/frame/gpu_frame.h b/core/frame/gpu_frame.h index c362d7066..eba2d5465 100644 --- a/core/frame/gpu_frame.h +++ b/core/frame/gpu_frame.h @@ -1,5 +1,7 @@ #pragma once +#include "frame_format.h" + #include #include @@ -34,6 +36,9 @@ public: virtual float y() const; virtual void translate(float x, float y); + virtual void mode(video_mode mode); + virtual video_mode mode() const; + static std::shared_ptr null() { static auto my_null_frame = std::make_shared(0,0); @@ -46,22 +51,4 @@ private: }; typedef std::shared_ptr gpu_frame_ptr; -inline void mix_audio_safe(std::vector& frame1, const std::vector& frame2) -{ - if(frame1.empty()) - frame1 = std::move(frame2); - else if(!frame2.empty()) - { - for(size_t n = 0; n < frame1.size(); ++n) - frame1[n] = static_cast(static_cast(frame1[n]) + static_cast(frame2[n]) & 0xFFFF); - } -} - -template -frame_ptr_type& mix_audio_safe(frame_ptr_type& frame1, const gpu_frame_ptr& frame2) -{ - mix_audio_safe(frame1->audio_data(), frame2->audio_data()); - return frame1; -} - } \ No newline at end of file diff --git a/core/frame/gpu_frame_processor.cpp b/core/frame/gpu_frame_processor.cpp index 9162d4f91..690a69923 100644 --- a/core/frame/gpu_frame_processor.cpp +++ b/core/frame/gpu_frame_processor.cpp @@ -3,11 +3,12 @@ #include "gpu_frame_processor.h" #include "gpu_frame.h" +#include "composite_gpu_frame.h" #include "frame_format.h" #include "../../common/exception/exceptions.h" #include "../../common/concurrency/executor.h" -#include "../../common/image/image.h" +#include "../../common/utility/memory.h" #include "../../common/gl/utility.h" #include @@ -76,6 +77,7 @@ struct gpu_frame_processor::implementation { context_.reset(new sf::Context()); context_->SetActive(true); + glEnable(GL_POLYGON_STIPPLE); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); @@ -84,16 +86,15 @@ struct gpu_frame_processor::implementation glViewport(0, 0, format_desc_.width, format_desc_.height); glLoadIdentity(); - input_.resize(2); - writing_.resize(2); + input_.resize(2, std::make_shared(format_desc_.width, format_desc_.height)); + writing_.resize(2, std::make_shared(format_desc_.width, format_desc_.height)); fbo_ = std::make_shared(format_desc_.width, format_desc_.height); output_frame_ = std::make_shared(format_desc_.width, format_desc_.height); index_ = 0; }); empty_frame_ = create_frame(format_desc.width, format_desc.height); - common::image::clear(empty_frame_->data(), empty_frame_->size()); - // Fill pipeline length + common::clear(empty_frame_->data(), empty_frame_->size()); for(int n = 0; n < 3; ++n) finished_frames_.push(empty_frame_); } @@ -113,6 +114,8 @@ struct gpu_frame_processor::implementation { boost::range::remove_erase(frames, nullptr); boost::range::remove_erase(frames, gpu_frame::null()); + auto composite_frame = std::make_shared(format_desc_.width, format_desc_.height); + boost::range::for_each(frames, std::bind(&composite_gpu_frame::add, composite_frame, std::placeholders::_1)); executor_.begin_invoke([=] { @@ -123,40 +126,33 @@ struct gpu_frame_processor::implementation // 2. Start asynchronous DMA transfer to video memory // Lock frames and give pointer ownership to OpenGL - boost::range::for_each(input_[index_], std::mem_fn(&gpu_frame::write_lock)); - writing_[index_] = input_[index_]; - input_[index_].clear(); + input_[index_]->write_lock(); + writing_[index_] = std::move(input_[index_]); // 1. Copy to page-locked memory - input_[next_index] = frames; + input_[next_index] = std::move(composite_frame); // 4. Output to external buffer if(output_frame_->read_unlock()) finished_frames_.push(output_frame_); - output_frame_ = nullptr; // 3. Draw to framebuffer and start asynchronous DMA transfer to page-locked memory // Clear framebuffer glClear(GL_COLOR_BUFFER_BIT); - - // Draw all frames to framebuffer - glLoadIdentity(); - boost::range::for_each(writing_[next_index], std::mem_fn(&gpu_frame::draw)); + writing_[next_index]->draw(); // Create an output frame output_frame_ = create_output_frame(); // Read from framebuffer into page-locked memory output_frame_->read_lock(GL_COLOR_ATTACHMENT0_EXT); + output_frame_->audio_data() = std::move(writing_[next_index]->audio_data()); // Unlock frames and give back pointer ownership - boost::range::for_each(writing_[next_index], std::mem_fn(&gpu_frame::write_unlock)); + writing_[next_index]->write_unlock(); - // Mix audio from composite frames into output frame - std::accumulate(writing_[next_index].begin(), writing_[next_index].end(), output_frame_, mix_audio_safe); - // Return frames to pool - writing_[next_index].clear(); + writing_[next_index].reset(); } catch(...) { @@ -213,8 +209,8 @@ struct gpu_frame_processor::implementation frame_buffer_ptr fbo_; int index_; - std::vector> input_; - std::vector> writing_; + std::vector input_; + std::vector writing_; gpu_frame_ptr output_frame_; tbb::concurrent_bounded_queue finished_frames_; diff --git a/core/producer/ffmpeg/audio/audio_decoder.cpp b/core/producer/ffmpeg/audio/audio_decoder.cpp index 381f846d7..e25b54d70 100644 --- a/core/producer/ffmpeg/audio/audio_decoder.cpp +++ b/core/producer/ffmpeg/audio/audio_decoder.cpp @@ -2,7 +2,7 @@ #include "audio_decoder.h" -#include "../../../../common/image/image.h" +#include "../../../../common/utility/memory.h" #include @@ -43,7 +43,7 @@ struct audio_decoder::implementation : boost::noncopyable { //either fill what's left of the chunk or copy all written_bytes that are left int targetLength = std::min((max_chunk_length - current_audio_chunk_offset_), written_bytes); - common::image::copy(current_chunk_data_ + current_audio_chunk_offset_, pDecomp, targetLength); + common::copy(current_chunk_data_ + current_audio_chunk_offset_, pDecomp, targetLength); written_bytes -= targetLength; current_audio_chunk_offset_ += targetLength; @@ -52,7 +52,7 @@ struct audio_decoder::implementation : boost::noncopyable if(current_audio_chunk_offset_ >= max_chunk_length) { if(max_chunk_length < static_cast(audio_packet->audio_frame_size)) - common::image::clear(current_chunk_data_ + max_chunk_length, audio_packet->audio_frame_size-max_chunk_length); + common::clear(current_chunk_data_ + max_chunk_length, audio_packet->audio_frame_size-max_chunk_length); else if(audio_packet->audio_frame_size < audio_packet->src_audio_frame_size) discard_bytes_ = audio_packet->src_audio_frame_size-audio_packet->audio_frame_size; diff --git a/core/producer/ffmpeg/ffmpeg_producer.cpp b/core/producer/ffmpeg/ffmpeg_producer.cpp index 5def640f4..ebae14b88 100644 --- a/core/producer/ffmpeg/ffmpeg_producer.cpp +++ b/core/producer/ffmpeg/ffmpeg_producer.cpp @@ -31,7 +31,7 @@ extern "C" #include "../../frame/frame_format.h" #include "../../../common/utility/find_file.h" #include "../../server.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include "../../../common/utility/scope_exit.h" #include diff --git a/core/producer/ffmpeg/input.cpp b/core/producer/ffmpeg/input.cpp index 6cf6f5b7f..fb1a7e5a5 100644 --- a/core/producer/ffmpeg/input.cpp +++ b/core/producer/ffmpeg/input.cpp @@ -3,7 +3,7 @@ #include "input.h" #include "../../frame/frame_format.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include "../../../common/utility/scope_exit.h" #include diff --git a/core/producer/ffmpeg/video/video_deinterlacer.cpp b/core/producer/ffmpeg/video/video_deinterlacer.cpp index e59c6d315..1ac528a0c 100644 --- a/core/producer/ffmpeg/video/video_deinterlacer.cpp +++ b/core/producer/ffmpeg/video/video_deinterlacer.cpp @@ -4,7 +4,7 @@ #include "../packet.h" -#include "../../../../common/image/image.h" +#include "../../../../common/utility/memory.h" #include #include diff --git a/core/producer/ffmpeg/video/video_transformer.cpp b/core/producer/ffmpeg/video/video_transformer.cpp deleted file mode 100644 index d88a7347d..000000000 --- a/core/producer/ffmpeg/video/video_transformer.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "../../../stdafx.h" - -#include "video_transformer.h" - -#include "../../../frame/frame_format.h" -#include "../../../../common/image/image.h" -#include "../../../frame/gpu_frame.h" -#include "../../../frame/gpu_frame.h" -#include "../../../frame/frame_factory.h" - -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4244) -#endif -extern "C" -{ - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS - #include -} -#if defined(_MSC_VER) -#pragma warning (pop) -#endif - -namespace caspar{ namespace ffmpeg{ - -typedef std::shared_ptr SwsContextPtr; - -// TODO: Remove and do copy right into frame -struct fill_frame -{ - fill_frame(size_t width, size_t height) - : frame(avcodec_alloc_frame(), av_free), buffer(static_cast(scalable_aligned_malloc(width*height*4, 16)), scalable_aligned_free) - { - avpicture_fill(reinterpret_cast(frame.get()), buffer.get(), PIX_FMT_BGRA, width, height); - } - const AVFramePtr frame; - const std::shared_ptr buffer; -}; -typedef std::shared_ptr fill_frame_ptr; - -struct video_transformer::implementation : boost::noncopyable -{ - video_packet_ptr execute(const video_packet_ptr video_packet) - { - assert(video_packet); - - if(!sws_context_) - { - double param; - sws_context_.reset(sws_getContext(video_packet->codec_context->width, video_packet->codec_context->height, video_packet->codec_context->pix_fmt, video_packet->format_desc.width, video_packet->format_desc.height, - PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext); - } - - //AVFrame avFrame; - //avcodec_get_frame_defaults(avFrame); - //avpicture_fill(reinterpret_cast(&avFrame), video_packet->frame->data(), PIX_FMT_BGRA, video_packet->frameFormat.width, video_packet->frameFormat.height); - - auto format_desc = video_packet->format_desc; - - fill_frame fill_frame(format_desc.width, format_desc.height); - video_packet->frame = factory_->create_frame(format_desc.width, format_desc.height); - int result = sws_scale(sws_context_.get(), video_packet->decoded_frame->data, video_packet->decoded_frame->linesize, 0, video_packet->codec_context->height, fill_frame.frame->data, fill_frame.frame->linesize); - video_packet->decoded_frame.reset(); // Free memory - - if(video_packet->codec->id == CODEC_ID_DVVIDEO) // Move up one field - { - size_t size = format_desc.width * format_desc.height * 4; - size_t linesize = format_desc.width * 4; - common::image::copy(video_packet->frame->data(), fill_frame.buffer.get() + linesize, size - linesize); - common::image::clear(video_packet->frame->data() + size - linesize, linesize); - } - else - { - // This copy should be unnecessary. But it seems that when mapping the frame memory to an avframe for scaling there are some artifacts in the picture. See line 59-61. - common::image::copy(video_packet->frame->data(), fill_frame.buffer.get(), video_packet->frame->size()); - } - - return video_packet; - } - - frame_factory_ptr factory_; - SwsContextPtr sws_context_; -}; - -video_transformer::video_transformer() : impl_(new implementation()){} -video_packet_ptr video_transformer::execute(const video_packet_ptr& video_packet){return impl_->execute(video_packet);} -void video_transformer::initialize(const frame_factory_ptr& factory){impl_->factory_ = factory; } -}} \ No newline at end of file diff --git a/core/producer/flash/flash_producer.cpp b/core/producer/flash/flash_producer.cpp index e64ae7ceb..6fd7c01d9 100644 --- a/core/producer/flash/flash_producer.cpp +++ b/core/producer/flash/flash_producer.cpp @@ -34,9 +34,12 @@ #include "../../server.h" #include "../../../common/concurrency/executor.h" #include "../../../common/concurrency/function_task.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include "../../../common/utility/scope_exit.h" +#include "../../frame/gpu_frame.h" +#include "../../frame/composite_gpu_frame.h" + #include #include #include @@ -63,8 +66,7 @@ struct flash_producer::implementation if(!boost::filesystem::exists(filename)) BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename))); - frame_buffer_.set_capacity(flash_producer::DEFAULT_BUFFER_SIZE); - last_frame_ = std::make_shared(format_desc_.width, format_desc_.height); + frame_buffer_.set_capacity(flash_producer::DEFAULT_BUFFER_SIZE); start(); } @@ -224,20 +226,36 @@ struct flash_producer::implementation } bool isProgressive = format_desc_.mode == video_mode::progressive || (flashax_container_->GetFPS() - format_desc_.fps/2 == 0); - frame_buffer_.push(isProgressive ? render_frame() : render_interlace_frame()); + + gpu_frame_ptr result; + + if(isProgressive) + result = render_frame(); + else + { + auto result = std::make_shared(format_desc_.width, format_desc_.height); + auto frame1 = render_frame(); + auto frame2 = render_frame(); + result->add(frame1); + result->add(frame2); + if(format_desc_.mode == video_mode::upper) + { + frame1->mode(video_mode::upper); + frame2->mode(video_mode::lower); + } + else + { + frame1->mode(video_mode::lower); + frame2->mode(video_mode::upper); + } + } + + frame_buffer_.push(result); is_empty_ = flashax_container_->IsEmpty(); } } - - bitmap_ptr render_interlace_frame() - { - bitmap_ptr frame1 = render_frame(); - bitmap_ptr frame2 = render_frame(); - common::image::copy(frame1->data(), frame2->data(), frame1->size()); - return frame1; - } - - bitmap_ptr render_frame() + + gpu_frame_ptr render_frame() { flashax_container_->Tick(); invalid_count_ = !flashax_container_->InvalidRectangle() ? std::min(2, invalid_count_+1) : 0; @@ -248,7 +266,7 @@ struct flash_producer::implementation { CASPAR_LOG(trace) << "Allocated bitmap"; frame = std::make_shared(format_desc_.width, format_desc_.height); - common::image::clear(frame->data(), frame->size()); + common::clear(frame->data(), frame->size()); } flashax_container_->DrawControl(frame->hdc()); @@ -258,11 +276,16 @@ struct flash_producer::implementation common::function_task::enqueue([=] { if(pool->try_push(frame)) - common::image::clear(frame->data(), frame->size()); + common::clear(frame->data(), frame->size()); }); }); } - return current_frame_; + + auto frame = factory_->create_frame(format_desc_); + auto bitmap = render_frame(); + common::copy(frame->data(), current_frame_->data(), current_frame_->size()); + + return frame; } gpu_frame_ptr get_frame() @@ -270,10 +293,7 @@ struct flash_producer::implementation if(!frame_buffer_.try_pop(last_frame_) && is_empty_) return gpu_frame::null(); - auto frame = factory_->create_frame(format_desc_); - common::image::copy(frame->data(), last_frame_->data(), last_frame_->size()); - - return frame; + return last_frame_; } void initialize(const frame_factory_ptr& factory) @@ -287,8 +307,8 @@ struct flash_producer::implementation CComObject* flashax_container_; - tbb::concurrent_bounded_queue frame_buffer_; - bitmap_ptr last_frame_; + tbb::concurrent_bounded_queue frame_buffer_; + gpu_frame_ptr last_frame_; bitmap_ptr current_frame_; std::wstring filename_; diff --git a/core/producer/image/image_loader.cpp b/core/producer/image/image_loader.cpp index 0bf56306f..a4293e8d4 100644 --- a/core/producer/image/image_loader.cpp +++ b/core/producer/image/image_loader.cpp @@ -5,7 +5,7 @@ #include "../../../common/exception/Exceptions.h" #include "../../frame/gpu_frame.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #if defined(_MSC_VER) #pragma warning (disable : 4714) // marked as __forceinline not inlined diff --git a/core/producer/image/image_producer.cpp b/core/producer/image/image_producer.cpp index 4b945ffa4..6718121e9 100644 --- a/core/producer/image/image_producer.cpp +++ b/core/producer/image/image_producer.cpp @@ -7,7 +7,7 @@ #include "../../frame/frame_format.h" #include "../../server.h" #include "../../../common/utility/find_file.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include @@ -33,7 +33,7 @@ struct image_producer : public frame_producer FreeImage_FlipVertical(bitmap.get()); frame_ = factory->create_frame(format_desc_); - common::image::copy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size()); + common::copy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size()); } const frame_format_desc& get_frame_format_desc() const { return format_desc_; } diff --git a/core/producer/image/image_scroll_producer.cpp b/core/producer/image/image_scroll_producer.cpp index 0bd071cd4..48cca8844 100644 --- a/core/producer/image/image_scroll_producer.cpp +++ b/core/producer/image/image_scroll_producer.cpp @@ -4,11 +4,13 @@ #include "image_loader.h" +#include "../../frame/gpu_frame.h" +#include "../../frame/composite_gpu_frame.h" #include "../../frame/frame_format.h" #include "../../frame/frame_factory.h" #include "../../server.h" #include "../../../common/utility/find_file.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include #include @@ -73,18 +75,18 @@ struct image_scroll_producer : public frame_producer image_height_ = std::max(height, format_desc_.height); image_ = std::shared_ptr(static_cast(scalable_aligned_malloc(image_width_*image_height_*4, 16))); - common::image::clear(image_.get(), image_width_*image_height_*4); + common::clear(image_.get(), image_width_*image_height_*4); unsigned char* pBits = FreeImage_GetBits(pBitmap.get()); for (size_t i = 0; i < height; ++i) - common::image::copy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4); + common::copy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4); } gpu_frame_ptr render_frame() { gpu_frame_ptr frame = factory_->create_frame(format_desc_); - common::image::clear(frame->data(), frame->size()); + common::clear(frame->data(), frame->size()); const int delta_x = direction_ == direction::Left ? speed_ : -speed_; const int delta_y = direction_ == direction::Up ? speed_ : -speed_; @@ -125,20 +127,33 @@ struct image_scroll_producer : public frame_producer return frame; } - - gpu_frame_ptr render_interlaced_frame() - { - gpu_frame_ptr next_frame1; - gpu_frame_ptr next_frame2; - tbb::parallel_invoke([&]{ next_frame1 = render_frame(); }, [&]{ next_frame2 = render_frame(); }); - common::image::copy_field(next_frame1->data(), next_frame2->data(), format_desc_.mode == video_mode::upper ? 1 : 0, format_desc_.width, format_desc_.height); - return next_frame1; - } - gpu_frame_ptr get_frame() - { - return format_desc_.mode == video_mode::progressive ? render_frame() : render_interlaced_frame(); + { + gpu_frame_ptr result; + if(format_desc_.mode == video_mode::progressive) + result = render_frame(); + else + { + auto result = std::make_shared(format_desc_.width, format_desc_.height); + gpu_frame_ptr frame1; + gpu_frame_ptr frame2; + tbb::parallel_invoke([&]{ frame1 = render_frame(); }, [&]{ frame2 = render_frame(); }); + result->add(frame1); + result->add(frame2); + if(format_desc_.mode == video_mode::upper) + { + frame1->mode(video_mode::upper); + frame2->mode(video_mode::lower); + } + else + { + frame1->mode(video_mode::lower); + frame2->mode(video_mode::upper); + } + } + + return result; } diff --git a/core/producer/transition/transition_producer.cpp b/core/producer/transition/transition_producer.cpp index 7d71f5f4a..5c4831f8e 100644 --- a/core/producer/transition/transition_producer.cpp +++ b/core/producer/transition/transition_producer.cpp @@ -26,7 +26,7 @@ #include "../../frame/composite_gpu_frame.h" #include "../../frame/frame_factory.h" -#include "../../../common/image/image.h" +#include "../../../common/utility/memory.h" #include "../../renderer/render_device.h" #include @@ -65,7 +65,7 @@ struct transition_producer::implementation : boost::noncopyable if(producer == nullptr) { auto frame = factory_->create_frame(format_desc_); - common::image::clear(frame->data(), frame->size()); + common::clear(frame->data(), frame->size()); return frame; } @@ -114,12 +114,23 @@ struct transition_producer::implementation : boost::noncopyable } else if(info_.type == transition_type::slide) { - dest_frame->translate(-1.0f+alpha, 0.0f); + if(info_.direction == transition_direction::from_left) + dest_frame->translate(-1.0f+alpha, 0.0f); + else if(info_.direction == transition_direction::from_right) + dest_frame->translate(1.0f-alpha, 0.0f); } else if(info_.type == transition_type::push) { - dest_frame->translate(-1.0f+alpha, 0.0f); - src_frame->translate(alpha, 0.0f); + if(info_.direction == transition_direction::from_left) + { + dest_frame->translate(-1.0f+alpha, 0.0f); + src_frame->translate(0.0f+alpha, 0.0f); + } + else if(info_.direction == transition_direction::from_right) + { + dest_frame->translate(1.0f-alpha, 0.0f); + src_frame->translate(0.0f-alpha, 0.0f); + } } return composite; } diff --git a/core/renderer/render_device.cpp b/core/renderer/render_device.cpp index b5550936d..343f4929d 100644 --- a/core/renderer/render_device.cpp +++ b/core/renderer/render_device.cpp @@ -1,5 +1,9 @@ #include "..\StdAfx.h" +#ifdef _MSC_VER +#pragma warning (disable : 4244) +#endif + #include "render_device.h" #include "layer.h" @@ -9,7 +13,7 @@ #include "../frame/gpu_frame_processor.h" #include "../../common/utility/scope_exit.h" -#include "../../common/image/image.h" +#include "../../common/utility/memory.h" #include @@ -45,7 +49,7 @@ std::vector render_frames(std::map& layers) struct render_device::implementation : boost::noncopyable { implementation(const caspar::frame_format_desc& format_desc, unsigned int index, const std::vector& consumers) - : consumers_(consumers), fmt_(format_desc), frame_processor_(new gpu_frame_processor(format_desc)) + : consumers_(consumers), fmt_(format_desc), frame_processor_(new gpu_frame_processor(format_desc)), needs_clock_(false) { is_running_ = true; if(consumers.empty()) @@ -56,6 +60,8 @@ struct render_device::implementation : boost::noncopyable BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("consumer") << msg_info("All consumers must have same frameformat as renderdevice.")); + needs_clock_ = !std::any_of(consumers.begin(), consumers.end(), std::mem_fn(&frame_consumer::has_sync_clock)); + frame_buffer_.set_capacity(3); display_thread_ = boost::thread([=]{display();}); render_thread_ = boost::thread([=]{render();}); @@ -74,7 +80,7 @@ struct render_device::implementation : boost::noncopyable void render() { - CASPAR_LOG(info) << L"Started render_device::render Thread"; + CASPAR_LOG(info) << L"Started render_device::render thread"; win32_exception::install_handler(); while(is_running_) @@ -100,20 +106,46 @@ struct render_device::implementation : boost::noncopyable } } - CASPAR_LOG(info) << L"Ended render_device::render Thread"; + CASPAR_LOG(info) << L"Ended render_device::render thread"; } + + struct video_sync_clock + { + video_sync_clock(const caspar::frame_format_desc& format_desc) + { + period_ = static_cast(get_frame_format_period(format_desc)*1000000.0); + time_ = boost::posix_time::microsec_clock::local_time(); + } + + void sync_video() + { + auto remaining = boost::posix_time::microseconds(period_) - (boost::posix_time::microsec_clock::local_time() - time_); + if(remaining > boost::posix_time::microseconds(5000)) + boost::this_thread::sleep(remaining - boost::posix_time::microseconds(5000)); + time_ = boost::posix_time::microsec_clock::local_time(); + } + + boost::posix_time::ptime time_; + long period_; + + }; void display() { - CASPAR_LOG(info) << L"Started render_device::display Thread"; + CASPAR_LOG(info) << L"Started render_device::display thread"; win32_exception::install_handler(); gpu_frame_ptr frame = frame_processor_->create_frame(fmt_.width, fmt_.height); - common::image::clear(frame->data(), frame->size()); + common::clear(frame->data(), frame->size()); std::deque prepared(3, frame); + + video_sync_clock clock(fmt_); while(is_running_) { + if(needs_clock_) + clock.sync_video(); + if(!frame_buffer_.try_pop(frame)) { CASPAR_LOG(trace) << "Display Buffer Underrun"; @@ -127,7 +159,7 @@ struct render_device::implementation : boost::noncopyable } } - CASPAR_LOG(info) << L"Ended render_device::display Thread"; + CASPAR_LOG(info) << L"Ended render_device::display thread"; } void send_frame(const gpu_frame_ptr& prepared_frame, const gpu_frame_ptr& next_frame) @@ -206,7 +238,7 @@ struct render_device::implementation : boost::noncopyable auto it = layers_.find(exLayer); return it != layers_.end() ? it->second.background() : nullptr; } - + boost::thread render_thread_; boost::thread display_thread_; @@ -221,6 +253,8 @@ struct render_device::implementation : boost::noncopyable tbb::atomic is_running_; gpu_frame_processor_ptr frame_processor_; + + bool needs_clock_; }; render_device::render_device(const caspar::frame_format_desc& format_desc, unsigned int index, const std::vector& consumers) @@ -234,4 +268,3 @@ frame_producer_ptr render_device::active(int exLayer) const {return impl_->activ frame_producer_ptr render_device::background(int exLayer) const {return impl_->background(exLayer);} const frame_format_desc& render_device::frame_format_desc() const{return impl_->fmt_;} }} - diff --git a/core/server.cpp b/core/server.cpp index 7312db42f..0e0bb8a88 100644 --- a/core/server.cpp +++ b/core/server.cpp @@ -2,12 +2,12 @@ #include "server.h" -#include "consumer/oal/oal_frame_consumer.h" +#include "consumer/oal/oal_consumer.h" #ifndef DISABLE_BLUEFISH -#include "consumer/bluefish/BlueFishVideoConsumer.h" +#include "consumer/bluefish/bluefish_consumer.h" #endif #include "consumer/decklink/DecklinkVideoConsumer.h" -#include "consumer/ogl/ogl_frame_consumer.h" +#include "consumer/ogl/ogl_consumer.h" #include @@ -17,7 +17,6 @@ #include "producer/flash/FlashAxContainer.h" #include "../common/io/AsyncEventServer.h" -#include "../common/io/SerialPort.h" #include "../common/utility/string_convert.h" #include @@ -42,14 +41,13 @@ struct server::implementation : boost::noncopyable setup_channels(pt); setup_controllers(pt); - if(!flash::FlashAxContainer::CheckForFlashSupport()) - CASPAR_LOG(error) << "No flashplayer activex-control installed. Flash support will be disabled"; + //if(!flash::FlashAxContainer::CheckForFlashSupport()) + // CASPAR_LOG(error) << "No flashplayer activex-control installed. Flash support will be disabled"; } ~implementation() { FreeImage_DeInitialise(); - serial_ports_.clear(); async_servers_.clear(); channels_.clear(); } @@ -98,16 +96,16 @@ struct server::implementation : boost::noncopyable stretch = ogl::stretch::uniform_to_fill; bool windowed = xml_consumer.second.get("windowed", false); - pConsumer = std::make_shared(format_desc, device, stretch, windowed); + pConsumer = std::make_shared(format_desc, device, stretch, windowed); } #ifndef DISABLE_BLUEFISH - else if(name == "bluefish") - pConsumer = caspar::bluefish::BlueFishVideoConsumer::Create(format_desc, xml_consumer.second.get("device", 0)); + else if(name == "bluefish") + pConsumer = std::make_shared(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false)); #endif else if(name == "decklink") pConsumer = std::make_shared(format_desc, xml_consumer.second.get("internalkey", false)); else if(name == "audio") - pConsumer = std::make_shared(format_desc); + pConsumer = std::make_shared(format_desc); if(pConsumer) consumers.push_back(pConsumer); @@ -140,23 +138,6 @@ struct server::implementation : boost::noncopyable asyncserver->Start(); async_servers_.push_back(asyncserver); } - else if(name == "serialcontroller") - { - std::wstring portName = common::widen(xml_controller.second.get("port-name")); - unsigned int baudRate = xml_controller.second.get("baud-rate"); - unsigned int dataBits = xml_controller.second.get("data-bits"); - unsigned int parity = xml_controller.second.get("parity"); - unsigned int stopBits = xml_controller.second.get("stop-bits"); - - baudRate = baudRate != 0 ? baudRate : 19200; - dataBits = dataBits != 0 ? dataBits : 8; - parity = parity != 0 ? parity : NOPARITY; - stopBits = stopBits != 0 ? stopBits : ONESTOPBIT; - - auto serialPort = std::make_shared(create_protocol(protocol), baudRate, parity, dataBits, stopBits, portName, xml_controller.second.get("spy", false)); - serialPort->Start(); - serial_ports_.push_back(serialPort); - } else BOOST_THROW_EXCEPTION(invalid_configuration() << arg_name_info(name) << msg_info("Invalid controller")); } @@ -180,7 +161,6 @@ struct server::implementation : boost::noncopyable BOOST_THROW_EXCEPTION(invalid_configuration() << arg_name_info("name") << arg_value_info(name) << msg_info("Invalid protocol")); } - std::vector serial_ports_; std::vector async_servers_; std::vector channels_; diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 000000000..371bf74e2 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,237 @@ +#define NOMINMAX + +#include +#include "timer.h" + +#include +#include +#include + +#include +#include +#include + +const unsigned int TEST_COUNT = 1000; +const unsigned int TEST_SIZE = 1920*1080*4; + +void test(const std::function& func) +{ + size_t size = TEST_SIZE; + void* src = scalable_aligned_malloc(size, 16); + void* dest = scalable_aligned_malloc(size, 16); + + timer timer; + double total_time = 0.0; + for(int i = 0 ;i < TEST_COUNT; ++i) + { + timer.start(); + func(dest, src, size); + total_time += timer.time(); + if(memcmp(dest, src, size) != 0) + std::cout << "ERROR"; + memset(src, rand(), size); // flush + } + + scalable_aligned_free(dest); + scalable_aligned_free(src); + + double unit_time = total_time/static_cast(TEST_COUNT); + std::cout << 1.0/unit_time*static_cast(TEST_SIZE)/1000000000.0 << " gb/s"; +} + +void* memcpy_SSE2_1(void* dest, const void* source, size_t size) +{ + __m128i* dest_128 = reinterpret_cast<__m128i*>(dest); + const __m128i* source_128 = reinterpret_cast(source); + + for(size_t n = 0; n < size/16; n += 8) + { + _mm_prefetch(reinterpret_cast(source_128+8), _MM_HINT_NTA); + _mm_prefetch(reinterpret_cast(source_128+12), _MM_HINT_NTA); + + __m128i xmm0 = _mm_load_si128(source_128++); + __m128i xmm1 = _mm_load_si128(source_128++); + __m128i xmm2 = _mm_load_si128(source_128++); + __m128i xmm3 = _mm_load_si128(source_128++); + + _mm_stream_si128(dest_128++, xmm0); + _mm_stream_si128(dest_128++, xmm1); + _mm_stream_si128(dest_128++, xmm2); + _mm_stream_si128(dest_128++, xmm3); + + __m128i xmm4 = _mm_load_si128(source_128++); + __m128i xmm5 = _mm_load_si128(source_128++); + __m128i xmm6 = _mm_load_si128(source_128++); + __m128i xmm7 = _mm_load_si128(source_128++); + + _mm_stream_si128(dest_128++, xmm4); + _mm_stream_si128(dest_128++, xmm5); + _mm_stream_si128(dest_128++, xmm6); + _mm_stream_si128(dest_128++, xmm7); + } + return dest; +} + +void* memcpy_SSE2_2(void* dest, const void* source, size_t num) +{ + __asm + { + mov esi, source; + mov edi, dest; + + mov ebx, num; + shr ebx, 7; + + cpy: + prefetchnta [esi+80h]; + prefetchnta [esi+0A0h]; + prefetchnta [esi+0C0h]; + prefetchnta [esi+0E0h]; + + movdqa xmm0, [esi+00h]; + movdqa xmm1, [esi+10h]; + movdqa xmm2, [esi+20h]; + movdqa xmm3, [esi+30h]; + + movntdq [edi+00h], xmm0; + movntdq [edi+10h], xmm1; + movntdq [edi+20h], xmm2; + movntdq [edi+30h], xmm3; + + movdqa xmm4, [esi+40h]; + movdqa xmm5, [esi+50h]; + movdqa xmm6, [esi+60h]; + movdqa xmm7, [esi+70h]; + + movntdq [edi+40h], xmm4; + movntdq [edi+50h], xmm5; + movntdq [edi+60h], xmm6; + movntdq [edi+70h], xmm7; + + lea edi,[edi+80h]; + lea esi,[esi+80h]; + dec ebx; + + jnz cpy; + } + return dest; +} + +void* memcpy_SSE2_3(void* dest, const void* source, size_t num) +{ + __asm + { + mov esi, source; + mov edi, dest; + + mov ebx, num; + shr ebx, 7; + + cpy: + prefetchnta [esi+80h]; + prefetchnta [esi+0C0h]; + + movdqa xmm0, [esi+00h]; + movdqa xmm1, [esi+10h]; + movdqa xmm2, [esi+20h]; + movdqa xmm3, [esi+30h]; + + movntdq [edi+00h], xmm0; + movntdq [edi+10h], xmm1; + movntdq [edi+20h], xmm2; + movntdq [edi+30h], xmm3; + + movdqa xmm4, [esi+40h]; + movdqa xmm5, [esi+50h]; + movdqa xmm6, [esi+60h]; + movdqa xmm7, [esi+70h]; + + movntdq [edi+40h], xmm4; + movntdq [edi+50h], xmm5; + movntdq [edi+60h], xmm6; + movntdq [edi+70h], xmm7; + + lea edi, [edi+80h]; + lea esi, [esi+80h]; + dec ebx; + jnz cpy; + } + return dest; +} + +void* memcpy_SSE2_3_tbb(void* dest, const void* source, size_t num) +{ + tbb::parallel_for(tbb::blocked_range(0, num/128), [&](const tbb::blocked_range& r) + { + memcpy_SSE2_3(reinterpret_cast(dest) + r.begin()*128, reinterpret_cast(source) + r.begin()*128, r.size()*128); + }, tbb::affinity_partitioner()); + + return dest; +} + +void* X_aligned_memcpy_sse2(void* dest, const void* src, size_t size_t) +{ + __asm + { + mov esi, src; //src pointer + mov edi, dest; //dest pointer + + mov ebx, size_t; //ebx is our counter + shr ebx, 7; //divide by 128 (8 * 128bit registers) + + + loop_copy: + prefetchnta 128[ESI]; //SSE2 prefetch + prefetchnta 160[ESI]; + prefetchnta 192[ESI]; + prefetchnta 224[ESI]; + + movdqa xmm0, 0[ESI]; //move data from src to registers + movdqa xmm1, 16[ESI]; + movdqa xmm2, 32[ESI]; + movdqa xmm3, 48[ESI]; + movdqa xmm4, 64[ESI]; + movdqa xmm5, 80[ESI]; + movdqa xmm6, 96[ESI]; + movdqa xmm7, 112[ESI]; + + movntdq 0[EDI], xmm0; //move data from registers to dest + movntdq 16[EDI], xmm1; + movntdq 32[EDI], xmm2; + movntdq 48[EDI], xmm3; + movntdq 64[EDI], xmm4; + movntdq 80[EDI], xmm5; + movntdq 96[EDI], xmm6; + movntdq 112[EDI], xmm7; + + add esi, 128; + add edi, 128; + dec ebx; + + jnz loop_copy; //loop please + } + return dest; +} + +int main(int argc, wchar_t* argv[]) +{ + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + test(memcpy); + std::cout << " memcpy" << std::endl; + test(memcpy_SSE2_1); + std::cout << " memcpy_SSE2_1" << std::endl; + test(memcpy_SSE2_2); + std::cout << " memcpy_SSE2_2" << std::endl; + test(memcpy_SSE2_3); + std::cout << " memcpy_SSE2_3" << std::endl; + test(memcpy_SSE2_3_tbb); + std::cout << " memcpy_SSE2_3_tbb" << std::endl; + test(X_aligned_memcpy_sse2); + std::cout << " X_aligned_memcpy_sse2" << std::endl; + + std::cout << "Press ENTER to continue... " << std::endl; + std::cin.ignore(std::numeric_limits::max(), '\n'); + + return 0; +} + diff --git a/test/test.vcxproj b/test/test.vcxproj new file mode 100644 index 000000000..1b852ea1b --- /dev/null +++ b/test/test.vcxproj @@ -0,0 +1,95 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {CE1CD805-3904-4E58-824E-09C027585991} + Win32Proj + test + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + + + false + ..\..\dependencies\tbb30_20100406oss\include;..\..\..\dependencies\tbb30_20100406oss\include;$(IncludePath) + ..\..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;$(LibraryPath) + $(SolutionDir)\$(ProjectName)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + AnySuitable + Speed + + + Console + true + true + true + tbb.lib; kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + NotUsing + + + + + + + + + + + \ No newline at end of file diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters new file mode 100644 index 000000000..88bc9b946 --- /dev/null +++ b/test/test.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {e218486c-9cba-405b-935b-6875a0b9b0d5} + + + + + memcpy + + + + + utility + + + \ No newline at end of file diff --git a/test/timer.h b/test/timer.h new file mode 100644 index 000000000..046a1a585 --- /dev/null +++ b/test/timer.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +class timer +{ +public: + timer() + { + QueryPerformanceFrequency(&freq_); + } + + void start() + { + QueryPerformanceCounter(&start_); + } + + double time() + { + LARGE_INTEGER time_; + QueryPerformanceCounter(&time_); + return static_cast(time_.QuadPart - start_.QuadPart) / static_cast(freq_.QuadPart); + } + +private: + LARGE_INTEGER freq_; + LARGE_INTEGER start_; +}; \ No newline at end of file -- 2.39.2