1 /*
2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 
27 /**
28  * This class encapsulates the array of Win32GraphicsDevices,
29  * allowing it to be accessed and recreated from multiple
30  * threads in a thread-safe manner.
31  *
32  * The MT-safeness of the array is assured in the following ways:
33  *      - hide the actual array being used so that access to
34  *        it can only be made from this class
35  *      - Do not delete the array until all references to the
36  *        array have released it.  That way, anyone that happens
37  *        to have a pointer to an element of the array can still
38  *        safely refer to that item, even if the situation has
39  *        changed and the array is out of date.
40  *      - ensure that the user of the array always gets a non-disposed
41  *        instance (before the user is handed over a reference to the
42  *        instance, a ref counter of the instance is increased atomically)
43  *      - The act of replacing an old encapsulated array
44  *        of devices with the new one is protected via common lock
45  *
46  * Expected usage patterns:
47  * 1. The array element will not be used outside of this code block.
48  *   {
49  *     // first, get the reference to the Devices instance through InstanceAccess
50  *     // subclass (this automatically increases ref count of this instance)
51  *     Devices::InstanceAccess devices; // increases the ref count of current instance
52  *     // Then the object can be used, for example, to retrieve the awt device.
53  *     // (note: ref count is not increased with GetDevice())
54  *     AwtWin32GraphicsDevice *dev = devices->GetDevice(idx);
55  *     dev->DoStuff();
56  *     Data data = dev->GetData();
57  *     return data;
58  *     // don't need to release the reference, it's done automatically in
59  *     // InstanceAccess destructor
60  *   }
61  *
62  * 2. The array element will be used outside of this code block (i.e.
63  *    saved for later use).
64  *   {
65  *     Devices::InstanceAccess devices; // increases the ref count
66  *     // next call increases the ref count of the instance again
67  *     AwtWin32GraphicsDevice *dev = devices->GetDeviceReference(idx);
68  *     wsdo->device = dev;
69  *     // we saved the ref to the device element, the first reference
70  *     // will be released automatically in the InstanceAccess destructor
71  *   }
72  *
73  *   {
74  *     wsdo->device->DoStuff(); // safe because we hold a reference
75  *     // then, sometime later (different thread, method, whatever)
76  *     // release the reference to the array element, which in
77  *     // turn will decrease the ref count of the instance of Devices class
78  *     // this element belongs to
79  *     wsdo->device->Release();
80  *     wsdo->device = NULL; // this reference can no longer be used
81  *   }
82  */
83 
84 #include "Devices.h"
85 #include "Trace.h"
86 #include "D3DPipelineManager.h"
87 
88 
89 /* Some helper functions (from awt_MMStub.h/cpp) */
90 
91 int g_nMonitorCounter;
92 int g_nMonitorLimit;
93 HMONITOR* g_hmpMonitors;
94 
95 // Callback for CountMonitors below
clb_fCountMonitors(HMONITOR hMon,HDC hDC,LPRECT rRect,LPARAM lP)96 BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP)
97 {
98     g_nMonitorCounter ++;
99     return TRUE;
100 }
101 
CountMonitors(void)102 int WINAPI CountMonitors(void)
103 {
104     g_nMonitorCounter = 0;
105     ::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, 0L);
106     return g_nMonitorCounter;
107 
108 }
109 
110 // Callback for CollectMonitors below
clb_fCollectMonitors(HMONITOR hMon,HDC hDC,LPRECT rRect,LPARAM lP)111 BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP)
112 {
113 
114     if ((g_nMonitorCounter < g_nMonitorLimit) && (NULL != g_hmpMonitors)) {
115         g_hmpMonitors[g_nMonitorCounter] = hMon;
116         g_nMonitorCounter ++;
117     }
118 
119     return TRUE;
120 }
121 
CollectMonitors(HMONITOR * hmpMonitors,int nNum)122 int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum)
123 {
124     int retCode = 0;
125 
126     if (NULL != hmpMonitors) {
127 
128         g_nMonitorCounter   = 0;
129         g_nMonitorLimit     = nNum;
130         g_hmpMonitors       = hmpMonitors;
131 
132         ::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, 0L);
133 
134         retCode             = g_nMonitorCounter;
135 
136         g_nMonitorCounter   = 0;
137         g_nMonitorLimit     = 0;
138         g_hmpMonitors       = NULL;
139 
140     }
141     return retCode;
142 }
143 
MonitorBounds(HMONITOR hmMonitor,RECT * rpBounds)144 BOOL WINAPI MonitorBounds(HMONITOR hmMonitor, RECT* rpBounds)
145 {
146     BOOL retCode = FALSE;
147 
148     if ((NULL != hmMonitor) && (NULL != rpBounds)) {
149         MONITORINFOEX miInfo;
150 
151         memset((void*)(&miInfo), 0, sizeof(MONITORINFOEX));
152         miInfo.cbSize = sizeof(MONITORINFOEX);
153 
154         if (TRUE == (retCode = ::GetMonitorInfo(hmMonitor, &miInfo))) {
155             (*rpBounds) = miInfo.rcMonitor;
156         }
157     }
158     return retCode;
159 }
160 
161 /* End of helper functions */
162 
163 Devices* Devices::theInstance = NULL;
164 CriticalSection Devices::arrayLock;
165 
166 /**
167  * Create a new Devices object with numDevices elements.
168  */
Devices(int numDevices)169 Devices::Devices(int numDevices)
170 {
171     J2dTraceLn1(J2D_TRACE_INFO, "Devices::Devices numDevices=%d", numDevices);
172     this->numDevices = numDevices;
173     this->refCount = 0;
174     devices = (AwtWin32GraphicsDevice**)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc,
175         numDevices, sizeof(AwtWin32GraphicsDevice *));
176 }
177 
178 /**
179  * Static method which updates the array of the devices
180  * while holding global lock.
181  *
182  * If the update was successful, method returns TRUE,
183  * otherwise it returns FALSE.
184  */
185 // static
UpdateInstance(JNIEnv * env)186 BOOL Devices::UpdateInstance(JNIEnv *env)
187 {
188     J2dTraceLn(J2D_TRACE_INFO, "Devices::UpdateInstance");
189 
190     int numScreens = CountMonitors();
191     HMONITOR *monHds = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc,
192             numScreens, sizeof(HMONITOR));
193     if (numScreens != CollectMonitors(monHds, numScreens)) {
194         J2dRlsTraceLn(J2D_TRACE_ERROR,
195                       "Devices::UpdateInstance: Failed to get all "\
196                       "monitor handles.");
197         free(monHds);
198         return FALSE;
199     }
200 
201     Devices *newDevices = new Devices(numScreens);
202     // This way we know that the array will not be disposed of
203     // at least until we replaced it with a new one.
204     newDevices->AddReference();
205 
206     // Create all devices first, then initialize them.  This allows
207     // correct configuration of devices after contruction of the
208     // primary device (which may not be device 0).
209     AwtWin32GraphicsDevice** rawDevices = newDevices->GetRawArray();
210     int i;
211     for (i = 0; i < numScreens; ++i) {
212         J2dTraceLn2(J2D_TRACE_VERBOSE, "  hmon[%d]=0x%x", i, monHds[i]);
213         rawDevices[i] = new AwtWin32GraphicsDevice(i, monHds[i], newDevices);
214     }
215     for (i = 0; i < numScreens; ++i) {
216         rawDevices[i]->Initialize();
217     }
218     {
219         CriticalSection::Lock l(arrayLock);
220 
221         // install the new devices array
222         Devices *oldDevices = theInstance;
223         theInstance = newDevices;
224 
225         if (oldDevices) {
226             // Invalidate the devices with indexes out of the new set of
227             // devices. This doesn't cover all cases when the device
228             // might should be invalidated (like if it's not the last device
229             // that was removed), but it will have to do for now.
230             int oldNumScreens = oldDevices->GetNumDevices();
231             int newNumScreens = theInstance->GetNumDevices();
232             J2dTraceLn(J2D_TRACE_VERBOSE, "  Invalidating removed devices");
233             for (int i = newNumScreens; i < oldNumScreens; i++) {
234                 // removed device, needs to be invalidated
235                 J2dTraceLn1(J2D_TRACE_WARNING,
236                             "Devices::UpdateInstance: device removed: %d", i);
237                 oldDevices->GetDevice(i)->Invalidate(env);
238             }
239             // Now that we have a new array in place, remove this (possibly the
240             // last) reference to the old instance.
241             oldDevices->Release();
242         }
243         D3DPipelineManager::HandleAdaptersChange((HMONITOR*)monHds,
244                                                  theInstance->GetNumDevices());
245     }
246     free(monHds);
247 
248     return TRUE;
249 }
250 
251 /**
252  * Add a reference to the array.  This could be someone that wants
253  * to register interest in the array, versus someone that actually
254  * holds a reference to an array item (in which case they would
255  * call GetDeviceReference() instead).  This mechanism can keep
256  * the array from being deleted when it has no elements being
257  * referenced but is still a valid array to use for new elements
258  * or references.
259  */
AddReference()260 void Devices::AddReference()
261 {
262     J2dTraceLn(J2D_TRACE_INFO, "Devices::AddReference");
263     CriticalSection::Lock l(arrayLock);
264     refCount++;
265     J2dTraceLn1(J2D_TRACE_VERBOSE, "  refCount=%d", refCount);
266 }
267 
268 /**
269  * Static method for getting a reference
270  * to the instance of the current devices array.
271  * The instance will automatically have reference count increased.
272  *
273  * The caller thus must call Release() when done dealing with
274  * the array.
275  */
276 // static
GetInstance()277 Devices* Devices::GetInstance()
278 {
279     J2dTraceLn(J2D_TRACE_INFO, "Devices::GetInstance");
280     CriticalSection::Lock l(arrayLock);
281     if (theInstance != NULL) {
282         theInstance->AddReference();
283     } else {
284         J2dTraceLn(J2D_TRACE_ERROR,
285                    "Devices::GetInstance NULL instance");
286     }
287     return theInstance;
288 }
289 
290 /**
291  * Retrieve a pointer to an item in the array and register a
292  * reference to the array.  This increases the refCount of the
293  * instance, used to track when the array can be deleted.
294  *
295  * This method must be called while holding a reference to the instance.
296  *
297  * If adjust parameter is true (default), adjust the index into the
298  * devices array so that it falls within the current devices array.
299  * This is needed because the devices array can be changed at any
300  * time, and the index may be from the old array. But in some
301  * cases we prefer to know that the index is incorrect.
302  *
303  */
GetDeviceReference(int index,BOOL adjust)304 AwtWin32GraphicsDevice *Devices::GetDeviceReference(int index,
305                                                     BOOL adjust)
306 {
307     J2dTraceLn2(J2D_TRACE_INFO,
308                 "Devices::GetDeviceReference index=%d adjust?=%d",
309                 index, adjust);
310 
311     AwtWin32GraphicsDevice * ret = GetDevice(index, adjust);
312     if (ret != NULL) {
313         AddReference();
314     }
315     return ret;
316 }
317 
318 /**
319  * Returns a reference to a device with the passed index.
320  *
321  * This method does not increase the ref count of the Devices instance.
322  *
323  * This method must be called while holding a reference to the instance.
324  */
GetDevice(int index,BOOL adjust)325 AwtWin32GraphicsDevice *Devices::GetDevice(int index, BOOL adjust)
326 {
327     J2dTraceLn2(J2D_TRACE_INFO,
328                 "Devices::GetDevice index=%d adjust?=%d",
329                 index, adjust);
330     if (index < 0 || index >= numDevices) {
331         if (!adjust) {
332             J2dTraceLn1(J2D_TRACE_WARNING,
333                         "Devices::GetDevice: "\
334                         "incorrect index %d, returning NULL.", index);
335             return NULL;
336         }
337         J2dTraceLn1(J2D_TRACE_WARNING,
338                     "Devices::GetDevice: "\
339                     "adjusted index %d to 0.", index);
340         index = 0;
341     }
342     return devices[index];
343 }
344 
345 /**
346  * Returns a raw reference to the incapsulated array.
347  *
348  * This method does not increase the ref count of the Devices instance.
349  *
350  * This method must be called while holding a reference to the instance.
351  */
GetRawArray()352 AwtWin32GraphicsDevice **Devices::GetRawArray()
353 {
354     J2dTraceLn(J2D_TRACE_INFO, "Devices::GetRawArray");
355     return devices;
356 }
357 
358 
359 /**
360  * Decreases the reference count of the array. If the refCount goes to 0,
361  * then there are no more references to the array and all of the
362  * array elements, the array itself, and this object can be destroyed.
363  *
364  * Returns the number of references left after it was decremented.
365  */
Release()366 int Devices::Release()
367 {
368     J2dTraceLn(J2D_TRACE_INFO, "Devices::Release");
369     CriticalSection::Lock l(arrayLock);
370 
371     int refs = --refCount;
372 
373     J2dTraceLn1(J2D_TRACE_VERBOSE, "  refCount=%d", refs);
374 
375     if (refs == 0) {
376         J2dTraceLn(J2D_TRACE_VERBOSE, "  disposing the array");
377         if (devices != NULL) {
378             for (int i = 0; i < numDevices; ++i) {
379                 if (devices[i] != NULL) {
380                     delete devices[i];
381                     devices[i] = NULL;
382                 }
383             }
384             free(devices);
385             // null out data, can help with debugging
386             devices = NULL;
387         }
388         // it's safe to delete the instance and only
389         // then release the static lock
390         delete this;
391         // for safety return immediately after committing suicide
392         // (note: can not reference refCount here!)
393         return refs;
394     } else if (refs < 0) {
395         J2dTraceLn1(J2D_TRACE_ERROR,
396                     "Devices::Release: Negative ref count! refCount=%d",
397                     refs);
398     }
399 
400     return refs;
401 }
402