1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #ifdef HAS_DX
12   #include "guilib/D3DResource.h"
13   #include <wrl/client.h>
14 #endif
15 
16 #include "threads/Event.h"
17 
18 
19 enum ECAPTURESTATE
20 {
21   CAPTURESTATE_WORKING,
22   CAPTURESTATE_NEEDSRENDER,
23   CAPTURESTATE_NEEDSREADOUT,
24   CAPTURESTATE_DONE,
25   CAPTURESTATE_FAILED,
26   CAPTURESTATE_NEEDSDELETE
27 };
28 
29 class CRenderCaptureBase
30 {
31   public:
32     CRenderCaptureBase();
33     virtual ~CRenderCaptureBase();
34 
35     /* \brief Called by the rendermanager to set the state, should not be called by anything else */
SetState(ECAPTURESTATE state)36     void SetState(ECAPTURESTATE state) { m_state = state; }
37 
38     /* \brief Called by the rendermanager to get the state, should not be called by anything else */
GetState()39     ECAPTURESTATE GetState() { return m_state;}
40 
41     /* \brief Called by the rendermanager to set the userstate, should not be called by anything else */
SetUserState(ECAPTURESTATE state)42     void SetUserState(ECAPTURESTATE state) { m_userState = state; }
43 
44     /* \brief Called by the code requesting the capture
45        \return CAPTURESTATE_WORKING when the capture is in progress,
46        CAPTURESTATE_DONE when the capture has succeeded,
47        CAPTURESTATE_FAILED when the capture has failed
48     */
GetUserState()49     ECAPTURESTATE GetUserState() { return m_userState; }
50 
51     /* \brief The internal event will be set when the rendermanager has captured and read a videoframe, or when it has failed
52        \return A reference to m_event
53     */
GetEvent()54     CEvent& GetEvent() { return m_event; }
55 
56     /* \brief Called by the rendermanager to set the flags, should not be called by anything else */
SetFlags(int flags)57     void SetFlags(int flags) { m_flags = flags; }
58 
59     /* \brief Called by the rendermanager to get the flags, should not be called by anything else */
GetFlags()60     int GetFlags() { return m_flags; }
61 
62     /* \brief Called by the rendermanager to set the width, should not be called by anything else */
SetWidth(unsigned int width)63     void  SetWidth(unsigned int width) { m_width = width; }
64 
65     /* \brief Called by the rendermanager to set the height, should not be called by anything else */
SetHeight(unsigned int height)66     void SetHeight(unsigned int height) { m_height = height; }
67 
68     /* \brief Called by the code requesting the capture to get the width */
GetWidth()69     unsigned int GetWidth() { return m_width; }
70 
71     /* \brief Called by the code requesting the capture to get the height */
GetHeight()72     unsigned int GetHeight() { return m_height; }
73 
74     /* \brief Called by the code requesting the capture to get the buffer where the videoframe is stored,
75        the format is BGRA, this buffer is only valid when GetUserState returns CAPTURESTATE_DONE.
76        The size of the buffer is GetWidth() * GetHeight() * 4.
77     */
GetPixels()78     uint8_t*  GetPixels() const { return m_pixels; }
79 
80     /* \brief Called by the rendermanager to know if the capture is readout async (using dma for example),
81        should not be called by anything else.
82     */
IsAsync()83     bool  IsAsync() { return m_asyncSupported; }
84 
85   protected:
86     bool UseOcclusionQuery();
87 
88     ECAPTURESTATE  m_state;     //state for the rendermanager
89     ECAPTURESTATE  m_userState; //state for the thread that wants the capture
90     int m_flags;
91     CEvent m_event;
92 
93     uint8_t*  m_pixels;
94     unsigned int m_width;
95     unsigned int m_height;
96     unsigned int m_bufferSize;
97 
98     //this is set after the first render
99     bool m_asyncSupported;
100     bool m_asyncChecked;
101 };
102 
103 #if defined(HAS_GL) || defined(HAS_GLES)
104 #include "system_gl.h"
105 
106 class CRenderCaptureGL : public CRenderCaptureBase
107 {
108   public:
109     CRenderCaptureGL();
110     ~CRenderCaptureGL() override;
111 
112     int   GetCaptureFormat();
113 
114     void  BeginRender();
115     void  EndRender();
116     void  ReadOut();
117 
118     void* GetRenderBuffer();
119 
120   private:
121     void   PboToBuffer();
122     GLuint m_pbo;
123     GLuint m_query;
124     bool   m_occlusionQuerySupported;
125 };
126 
127 //used instead of typedef CRenderCaptureGL CRenderCapture
128 //since C++ doesn't allow you to forward declare a typedef
129 class CRenderCapture : public CRenderCaptureGL
130 {
131   public:
132     CRenderCapture() = default;
133 };
134 
135 #elif HAS_DX /*HAS_GL*/
136 
137 class CRenderCaptureDX : public CRenderCaptureBase, public ID3DResource
138 {
139   public:
140     CRenderCaptureDX();
141     ~CRenderCaptureDX();
142 
143     int GetCaptureFormat();
144 
145     void BeginRender();
146     void EndRender();
147     void ReadOut();
148 
149     void OnDestroyDevice(bool fatal) override;
OnCreateDevice()150     void OnCreateDevice() override {};
GetTarget()151     CD3DTexture& GetTarget() { return m_renderTex; }
152 
153   private:
154     void SurfaceToBuffer();
155     void CleanupDX();
156 
157     unsigned int m_surfaceWidth;
158     unsigned int m_surfaceHeight;
159     Microsoft::WRL::ComPtr<ID3D11Query> m_query;
160     CD3DTexture m_renderTex;
161     CD3DTexture m_copyTex;
162 };
163 
164 class CRenderCapture : public CRenderCaptureDX
165 {
166   public:
CRenderCapture()167     CRenderCapture() {};
168 };
169 
170 #endif
171